[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

title

Body

[close]

/wp-admin/includes/ -> class-wp-posts-list-table.php (source)

   1  <?php
   2  /**
   3   * List Table API: WP_Posts_List_Table class
   4   *
   5   * @package WordPress
   6   * @subpackage Administration
   7   * @since 3.1.0
   8   */
   9  
  10  /**
  11   * Core class used to implement displaying posts in a list table.
  12   *
  13   * @since 3.1.0
  14   * @access private
  15   *
  16   * @see WP_List_Table
  17   */
  18  class WP_Posts_List_Table extends WP_List_Table {
  19  
  20      /**
  21       * Whether the items should be displayed hierarchically or linearly.
  22       *
  23       * @since 3.1.0
  24       * @var bool
  25       */
  26      protected $hierarchical_display;
  27  
  28      /**
  29       * Holds the number of pending comments for each post.
  30       *
  31       * @since 3.1.0
  32       * @var array
  33       */
  34      protected $comment_pending_count;
  35  
  36      /**
  37       * Holds the number of posts for this user.
  38       *
  39       * @since 3.1.0
  40       * @var int
  41       */
  42      private $user_posts_count;
  43  
  44      /**
  45       * Holds the number of posts which are sticky.
  46       *
  47       * @since 3.1.0
  48       * @var int
  49       */
  50      private $sticky_posts_count = 0;
  51  
  52      private $is_trash;
  53  
  54      /**
  55       * Current level for output.
  56       *
  57       * @since 4.3.0
  58       * @var int
  59       */
  60      protected $current_level = 0;
  61  
  62      /**
  63       * Constructor.
  64       *
  65       * @since 3.1.0
  66       *
  67       * @see WP_List_Table::__construct() for more information on default arguments.
  68       *
  69       * @global WP_Post_Type $post_type_object
  70       * @global wpdb         $wpdb
  71       *
  72       * @param array $args An associative array of arguments.
  73       */
  74  	public function __construct( $args = array() ) {
  75          global $post_type_object, $wpdb;
  76  
  77          parent::__construct(
  78              array(
  79                  'plural' => 'posts',
  80                  'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
  81              )
  82          );
  83  
  84          $post_type        = $this->screen->post_type;
  85          $post_type_object = get_post_type_object( $post_type );
  86  
  87          $exclude_states         = get_post_stati(
  88              array(
  89                  'show_in_admin_all_list' => false,
  90              )
  91          );
  92          $this->user_posts_count = intval(
  93              $wpdb->get_var(
  94                  $wpdb->prepare(
  95                      "
  96              SELECT COUNT( 1 )
  97              FROM $wpdb->posts
  98              WHERE post_type = %s
  99              AND post_status NOT IN ( '" . implode( "','", $exclude_states ) . "' )
 100              AND post_author = %d
 101          ",
 102                      $post_type,
 103                      get_current_user_id()
 104                  )
 105              )
 106          );
 107  
 108          if ( $this->user_posts_count && ! current_user_can( $post_type_object->cap->edit_others_posts ) && empty( $_REQUEST['post_status'] ) && empty( $_REQUEST['all_posts'] ) && empty( $_REQUEST['author'] ) && empty( $_REQUEST['show_sticky'] ) ) {
 109              $_GET['author'] = get_current_user_id();
 110          }
 111  
 112          if ( 'post' === $post_type && $sticky_posts = get_option( 'sticky_posts' ) ) {
 113              $sticky_posts             = implode( ', ', array_map( 'absint', (array) $sticky_posts ) );
 114              $this->sticky_posts_count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT( 1 ) FROM $wpdb->posts WHERE post_type = %s AND post_status NOT IN ('trash', 'auto-draft') AND ID IN ($sticky_posts)", $post_type ) );
 115          }
 116      }
 117  
 118      /**
 119       * Sets whether the table layout should be hierarchical or not.
 120       *
 121       * @since 4.2.0
 122       *
 123       * @param bool $display Whether the table layout should be hierarchical.
 124       */
 125  	public function set_hierarchical_display( $display ) {
 126          $this->hierarchical_display = $display;
 127      }
 128  
 129      /**
 130       * @return bool
 131       */
 132  	public function ajax_user_can() {
 133          return current_user_can( get_post_type_object( $this->screen->post_type )->cap->edit_posts );
 134      }
 135  
 136      /**
 137       * @global array    $avail_post_stati
 138       * @global WP_Query $wp_query
 139       * @global int      $per_page
 140       * @global string   $mode
 141       */
 142  	public function prepare_items() {
 143          global $avail_post_stati, $wp_query, $per_page, $mode;
 144  
 145          // is going to call wp()
 146          $avail_post_stati = wp_edit_posts_query();
 147  
 148          $this->set_hierarchical_display( is_post_type_hierarchical( $this->screen->post_type ) && 'menu_order title' === $wp_query->query['orderby'] );
 149  
 150          $post_type = $this->screen->post_type;
 151          $per_page  = $this->get_items_per_page( 'edit_' . $post_type . '_per_page' );
 152  
 153          /** This filter is documented in wp-admin/includes/post.php */
 154          $per_page = apply_filters( 'edit_posts_per_page', $per_page, $post_type );
 155  
 156          if ( $this->hierarchical_display ) {
 157              $total_items = $wp_query->post_count;
 158          } elseif ( $wp_query->found_posts || $this->get_pagenum() === 1 ) {
 159              $total_items = $wp_query->found_posts;
 160          } else {
 161              $post_counts = (array) wp_count_posts( $post_type, 'readable' );
 162  
 163              if ( isset( $_REQUEST['post_status'] ) && in_array( $_REQUEST['post_status'], $avail_post_stati ) ) {
 164                  $total_items = $post_counts[ $_REQUEST['post_status'] ];
 165              } elseif ( isset( $_REQUEST['show_sticky'] ) && $_REQUEST['show_sticky'] ) {
 166                  $total_items = $this->sticky_posts_count;
 167              } elseif ( isset( $_GET['author'] ) && $_GET['author'] == get_current_user_id() ) {
 168                  $total_items = $this->user_posts_count;
 169              } else {
 170                  $total_items = array_sum( $post_counts );
 171  
 172                  // Subtract post types that are not included in the admin all list.
 173                  foreach ( get_post_stati( array( 'show_in_admin_all_list' => false ) ) as $state ) {
 174                      $total_items -= $post_counts[ $state ];
 175                  }
 176              }
 177          }
 178  
 179          if ( ! empty( $_REQUEST['mode'] ) ) {
 180              $mode = $_REQUEST['mode'] === 'excerpt' ? 'excerpt' : 'list';
 181              set_user_setting( 'posts_list_mode', $mode );
 182          } else {
 183              $mode = get_user_setting( 'posts_list_mode', 'list' );
 184          }
 185  
 186          $this->is_trash = isset( $_REQUEST['post_status'] ) && $_REQUEST['post_status'] === 'trash';
 187  
 188          $this->set_pagination_args(
 189              array(
 190                  'total_items' => $total_items,
 191                  'per_page'    => $per_page,
 192              )
 193          );
 194      }
 195  
 196      /**
 197       * @return bool
 198       */
 199  	public function has_items() {
 200          return have_posts();
 201      }
 202  
 203      /**
 204       */
 205  	public function no_items() {
 206          if ( isset( $_REQUEST['post_status'] ) && 'trash' === $_REQUEST['post_status'] ) {
 207              echo get_post_type_object( $this->screen->post_type )->labels->not_found_in_trash;
 208          } else {
 209              echo get_post_type_object( $this->screen->post_type )->labels->not_found;
 210          }
 211      }
 212  
 213      /**
 214       * Determine if the current view is the "All" view.
 215       *
 216       * @since 4.2.0
 217       *
 218       * @return bool Whether the current view is the "All" view.
 219       */
 220  	protected function is_base_request() {
 221          $vars = $_GET;
 222          unset( $vars['paged'] );
 223  
 224          if ( empty( $vars ) ) {
 225              return true;
 226          } elseif ( 1 === count( $vars ) && ! empty( $vars['post_type'] ) ) {
 227              return $this->screen->post_type === $vars['post_type'];
 228          }
 229  
 230          return 1 === count( $vars ) && ! empty( $vars['mode'] );
 231      }
 232  
 233      /**
 234       * Helper to create links to edit.php with params.
 235       *
 236       * @since 4.4.0
 237       *
 238       * @param string[] $args  Associative array of URL parameters for the link.
 239       * @param string   $label Link text.
 240       * @param string   $class Optional. Class attribute. Default empty string.
 241       * @return string The formatted link string.
 242       */
 243  	protected function get_edit_link( $args, $label, $class = '' ) {
 244          $url = add_query_arg( $args, 'edit.php' );
 245  
 246          $class_html = $aria_current = '';
 247          if ( ! empty( $class ) ) {
 248              $class_html = sprintf(
 249                  ' class="%s"',
 250                  esc_attr( $class )
 251              );
 252  
 253              if ( 'current' === $class ) {
 254                  $aria_current = ' aria-current="page"';
 255              }
 256          }
 257  
 258          return sprintf(
 259              '<a href="%s"%s%s>%s</a>',
 260              esc_url( $url ),
 261              $class_html,
 262              $aria_current,
 263              $label
 264          );
 265      }
 266  
 267      /**
 268       * @global array $locked_post_status This seems to be deprecated.
 269       * @global array $avail_post_stati
 270       * @return array
 271       */
 272  	protected function get_views() {
 273          global $locked_post_status, $avail_post_stati;
 274  
 275          $post_type = $this->screen->post_type;
 276  
 277          if ( ! empty( $locked_post_status ) ) {
 278              return array();
 279          }
 280  
 281          $status_links = array();
 282          $num_posts    = wp_count_posts( $post_type, 'readable' );
 283          $total_posts  = array_sum( (array) $num_posts );
 284          $class        = '';
 285  
 286          $current_user_id = get_current_user_id();
 287          $all_args        = array( 'post_type' => $post_type );
 288          $mine            = '';
 289  
 290          // Subtract post types that are not included in the admin all list.
 291          foreach ( get_post_stati( array( 'show_in_admin_all_list' => false ) ) as $state ) {
 292              $total_posts -= $num_posts->$state;
 293          }
 294  
 295          if ( $this->user_posts_count && $this->user_posts_count !== $total_posts ) {
 296              if ( isset( $_GET['author'] ) && ( $_GET['author'] == $current_user_id ) ) {
 297                  $class = 'current';
 298              }
 299  
 300              $mine_args = array(
 301                  'post_type' => $post_type,
 302                  'author'    => $current_user_id,
 303              );
 304  
 305              $mine_inner_html = sprintf(
 306                  _nx(
 307                      'Mine <span class="count">(%s)</span>',
 308                      'Mine <span class="count">(%s)</span>',
 309                      $this->user_posts_count,
 310                      'posts'
 311                  ),
 312                  number_format_i18n( $this->user_posts_count )
 313              );
 314  
 315              $mine = $this->get_edit_link( $mine_args, $mine_inner_html, $class );
 316  
 317              $all_args['all_posts'] = 1;
 318              $class                 = '';
 319          }
 320  
 321          if ( empty( $class ) && ( $this->is_base_request() || isset( $_REQUEST['all_posts'] ) ) ) {
 322              $class = 'current';
 323          }
 324  
 325          $all_inner_html = sprintf(
 326              _nx(
 327                  'All <span class="count">(%s)</span>',
 328                  'All <span class="count">(%s)</span>',
 329                  $total_posts,
 330                  'posts'
 331              ),
 332              number_format_i18n( $total_posts )
 333          );
 334  
 335          $status_links['all'] = $this->get_edit_link( $all_args, $all_inner_html, $class );
 336          if ( $mine ) {
 337              $status_links['mine'] = $mine;
 338          }
 339  
 340          foreach ( get_post_stati( array( 'show_in_admin_status_list' => true ), 'objects' ) as $status ) {
 341              $class = '';
 342  
 343              $status_name = $status->name;
 344  
 345              if ( ! in_array( $status_name, $avail_post_stati ) || empty( $num_posts->$status_name ) ) {
 346                  continue;
 347              }
 348  
 349              if ( isset( $_REQUEST['post_status'] ) && $status_name === $_REQUEST['post_status'] ) {
 350                  $class = 'current';
 351              }
 352  
 353              $status_args = array(
 354                  'post_status' => $status_name,
 355                  'post_type'   => $post_type,
 356              );
 357  
 358              $status_label = sprintf(
 359                  translate_nooped_plural( $status->label_count, $num_posts->$status_name ),
 360                  number_format_i18n( $num_posts->$status_name )
 361              );
 362  
 363              $status_links[ $status_name ] = $this->get_edit_link( $status_args, $status_label, $class );
 364          }
 365  
 366          if ( ! empty( $this->sticky_posts_count ) ) {
 367              $class = ! empty( $_REQUEST['show_sticky'] ) ? 'current' : '';
 368  
 369              $sticky_args = array(
 370                  'post_type'   => $post_type,
 371                  'show_sticky' => 1,
 372              );
 373  
 374              $sticky_inner_html = sprintf(
 375                  _nx(
 376                      'Sticky <span class="count">(%s)</span>',
 377                      'Sticky <span class="count">(%s)</span>',
 378                      $this->sticky_posts_count,
 379                      'posts'
 380                  ),
 381                  number_format_i18n( $this->sticky_posts_count )
 382              );
 383  
 384              $sticky_link = array(
 385                  'sticky' => $this->get_edit_link( $sticky_args, $sticky_inner_html, $class ),
 386              );
 387  
 388              // Sticky comes after Publish, or if not listed, after All.
 389              $split        = 1 + array_search( ( isset( $status_links['publish'] ) ? 'publish' : 'all' ), array_keys( $status_links ) );
 390              $status_links = array_merge( array_slice( $status_links, 0, $split ), $sticky_link, array_slice( $status_links, $split ) );
 391          }
 392  
 393          return $status_links;
 394      }
 395  
 396      /**
 397       * @return array
 398       */
 399  	protected function get_bulk_actions() {
 400          $actions       = array();
 401          $post_type_obj = get_post_type_object( $this->screen->post_type );
 402  
 403          if ( current_user_can( $post_type_obj->cap->edit_posts ) ) {
 404              if ( $this->is_trash ) {
 405                  $actions['untrash'] = __( 'Restore' );
 406              } else {
 407                  $actions['edit'] = __( 'Edit' );
 408              }
 409          }
 410  
 411          if ( current_user_can( $post_type_obj->cap->delete_posts ) ) {
 412              if ( $this->is_trash || ! EMPTY_TRASH_DAYS ) {
 413                  $actions['delete'] = __( 'Delete Permanently' );
 414              } else {
 415                  $actions['trash'] = __( 'Move to Trash' );
 416              }
 417          }
 418  
 419          return $actions;
 420      }
 421  
 422      /**
 423       * Displays a categories drop-down for filtering on the Posts list table.
 424       *
 425       * @since 4.6.0
 426       *
 427       * @global int $cat Currently selected category.
 428       *
 429       * @param string $post_type Post type slug.
 430       */
 431  	protected function categories_dropdown( $post_type ) {
 432          global $cat;
 433  
 434          /**
 435           * Filters whether to remove the 'Categories' drop-down from the post list table.
 436           *
 437           * @since 4.6.0
 438           *
 439           * @param bool   $disable   Whether to disable the categories drop-down. Default false.
 440           * @param string $post_type Post type slug.
 441           */
 442          if ( false !== apply_filters( 'disable_categories_dropdown', false, $post_type ) ) {
 443              return;
 444          }
 445  
 446          if ( is_object_in_taxonomy( $post_type, 'category' ) ) {
 447              $dropdown_options = array(
 448                  'show_option_all' => get_taxonomy( 'category' )->labels->all_items,
 449                  'hide_empty'      => 0,
 450                  'hierarchical'    => 1,
 451                  'show_count'      => 0,
 452                  'orderby'         => 'name',
 453                  'selected'        => $cat,
 454              );
 455  
 456              echo '<label class="screen-reader-text" for="cat">' . __( 'Filter by category' ) . '</label>';
 457              wp_dropdown_categories( $dropdown_options );
 458          }
 459      }
 460  
 461      /**
 462       * Displays a formats drop-down for filtering items.
 463       *
 464       * @since 5.2.0
 465       * @access protected
 466       *
 467       * @param string $post_type Post type key.
 468       */
 469  	protected function formats_dropdown( $post_type ) {
 470          /**
 471           * Filters whether to remove the 'Formats' drop-down from the post list table.
 472           *
 473           * @since 5.2.0
 474           *
 475           * @param bool $disable Whether to disable the drop-down. Default false.
 476           */
 477          if ( apply_filters( 'disable_formats_dropdown', false ) ) {
 478              return;
 479          }
 480  
 481          // Make sure the dropdown shows only formats with a post count greater than 0.
 482          $used_post_formats = get_terms(
 483              array(
 484                  'taxonomy'   => 'post_format',
 485                  'hide_empty' => true,
 486              )
 487          );
 488  
 489          /*
 490           * Return if the post type doesn't have post formats, or there are no posts using formats,
 491           * or if we're in the trash.
 492           */
 493          if ( ! is_object_in_taxonomy( $post_type, 'post_format' ) || ! $used_post_formats || $this->is_trash ) {
 494              return;
 495          }
 496  
 497          $displayed_post_format = isset( $_GET['post_format'] ) ? $_GET['post_format'] : '';
 498          ?>
 499          <label for="filter-by-format" class="screen-reader-text"><?php _e( 'Filter by post format' ); ?></label>
 500          <select name="post_format" id="filter-by-format">
 501              <option<?php selected( $displayed_post_format, '' ); ?> value=""><?php _e( 'All formats' ); ?></option>
 502              <?php
 503              foreach ( $used_post_formats as $used_post_format ) {
 504                  // Post format slug.
 505                  $slug = str_replace( 'post-format-', '', $used_post_format->slug );
 506                  // Pretty, translated version of the post format slug.
 507                  $pretty_name = get_post_format_string( $slug );
 508                  // Skip the standard post format.
 509                  if ( 'standard' === $slug ) {
 510                      continue;
 511                  }
 512                  ?>
 513                  <option<?php selected( $displayed_post_format, $slug ); ?> value="<?php echo esc_attr( $slug ); ?>"><?php echo esc_html( $pretty_name ); ?></option>
 514                  <?php
 515              }
 516              ?>
 517          </select>
 518          <?php
 519      }
 520  
 521      /**
 522       * @param string $which
 523       */
 524  	protected function extra_tablenav( $which ) {
 525          ?>
 526          <div class="alignleft actions">
 527          <?php
 528          if ( 'top' === $which && ! is_singular() ) {
 529              ob_start();
 530  
 531              $this->months_dropdown( $this->screen->post_type );
 532              $this->categories_dropdown( $this->screen->post_type );
 533              $this->formats_dropdown( $this->screen->post_type );
 534  
 535              /**
 536               * Fires before the Filter button on the Posts and Pages list tables.
 537               *
 538               * The Filter button allows sorting by date and/or category on the
 539               * Posts list table, and sorting by date on the Pages list table.
 540               *
 541               * @since 2.1.0
 542               * @since 4.4.0 The `$post_type` parameter was added.
 543               * @since 4.6.0 The `$which` parameter was added.
 544               *
 545               * @param string $post_type The post type slug.
 546               * @param string $which     The location of the extra table nav markup:
 547               *                          'top' or 'bottom' for WP_Posts_List_Table,
 548               *                          'bar' for WP_Media_List_Table.
 549               */
 550              do_action( 'restrict_manage_posts', $this->screen->post_type, $which );
 551  
 552              $output = ob_get_clean();
 553  
 554              if ( ! empty( $output ) ) {
 555                  echo $output;
 556                  submit_button( __( 'Filter' ), '', 'filter_action', false, array( 'id' => 'post-query-submit' ) );
 557              }
 558          }
 559  
 560          if ( $this->is_trash && current_user_can( get_post_type_object( $this->screen->post_type )->cap->edit_others_posts ) && $this->has_items() ) {
 561              submit_button( __( 'Empty Trash' ), 'apply', 'delete_all', false );
 562          }
 563          ?>
 564          </div>
 565          <?php
 566          /**
 567           * Fires immediately following the closing "actions" div in the tablenav for the posts
 568           * list table.
 569           *
 570           * @since 4.4.0
 571           *
 572           * @param string $which The location of the extra table nav markup: 'top' or 'bottom'.
 573           */
 574          do_action( 'manage_posts_extra_tablenav', $which );
 575      }
 576  
 577      /**
 578       * @return string
 579       */
 580  	public function current_action() {
 581          if ( isset( $_REQUEST['delete_all'] ) || isset( $_REQUEST['delete_all2'] ) ) {
 582              return 'delete_all';
 583          }
 584  
 585          return parent::current_action();
 586      }
 587  
 588      /**
 589       * @return array
 590       */
 591  	protected function get_table_classes() {
 592          return array( 'widefat', 'fixed', 'striped', is_post_type_hierarchical( $this->screen->post_type ) ? 'pages' : 'posts' );
 593      }
 594  
 595      /**
 596       * @return array
 597       */
 598  	public function get_columns() {
 599          $post_type = $this->screen->post_type;
 600  
 601          $posts_columns = array();
 602  
 603          $posts_columns['cb'] = '<input type="checkbox" />';
 604  
 605          /* translators: manage posts column name */
 606          $posts_columns['title'] = _x( 'Title', 'column name' );
 607  
 608          if ( post_type_supports( $post_type, 'author' ) ) {
 609              $posts_columns['author'] = __( 'Author' );
 610          }
 611  
 612          $taxonomies = get_object_taxonomies( $post_type, 'objects' );
 613          $taxonomies = wp_filter_object_list( $taxonomies, array( 'show_admin_column' => true ), 'and', 'name' );
 614  
 615          /**
 616           * Filters the taxonomy columns in the Posts list table.
 617           *
 618           * The dynamic portion of the hook name, `$post_type`, refers to the post
 619           * type slug.
 620           *
 621           * @since 3.5.0
 622           *
 623           * @param string[] $taxonomies Array of taxonomy names to show columns for.
 624           * @param string   $post_type  The post type.
 625           */
 626          $taxonomies = apply_filters( "manage_taxonomies_for_{$post_type}_columns", $taxonomies, $post_type );
 627          $taxonomies = array_filter( $taxonomies, 'taxonomy_exists' );
 628  
 629          foreach ( $taxonomies as $taxonomy ) {
 630              if ( 'category' === $taxonomy ) {
 631                  $column_key = 'categories';
 632              } elseif ( 'post_tag' === $taxonomy ) {
 633                  $column_key = 'tags';
 634              } else {
 635                  $column_key = 'taxonomy-' . $taxonomy;
 636              }
 637  
 638              $posts_columns[ $column_key ] = get_taxonomy( $taxonomy )->labels->name;
 639          }
 640  
 641          $post_status = ! empty( $_REQUEST['post_status'] ) ? $_REQUEST['post_status'] : 'all';
 642          if ( post_type_supports( $post_type, 'comments' ) && ! in_array( $post_status, array( 'pending', 'draft', 'future' ) ) ) {
 643              $posts_columns['comments'] = '<span class="vers comment-grey-bubble" title="' . esc_attr__( 'Comments' ) . '"><span class="screen-reader-text">' . __( 'Comments' ) . '</span></span>';
 644          }
 645  
 646          $posts_columns['date'] = __( 'Date' );
 647  
 648          if ( 'page' === $post_type ) {
 649  
 650              /**
 651               * Filters the columns displayed in the Pages list table.
 652               *
 653               * @since 2.5.0
 654               *
 655               * @param string[] $post_columns An associative array of column headings.
 656               */
 657              $posts_columns = apply_filters( 'manage_pages_columns', $posts_columns );
 658          } else {
 659  
 660              /**
 661               * Filters the columns displayed in the Posts list table.
 662               *
 663               * @since 1.5.0
 664               *
 665               * @param string[] $post_columns An associative array of column headings.
 666               * @param string   $post_type    The post type slug.
 667               */
 668              $posts_columns = apply_filters( 'manage_posts_columns', $posts_columns, $post_type );
 669          }
 670  
 671          /**
 672           * Filters the columns displayed in the Posts list table for a specific post type.
 673           *
 674           * The dynamic portion of the hook name, `$post_type`, refers to the post type slug.
 675           *
 676           * @since 3.0.0
 677           *
 678           * @param string[] $post_columns An associative array of column headings.
 679           */
 680          return apply_filters( "manage_{$post_type}_posts_columns", $posts_columns );
 681      }
 682  
 683      /**
 684       * @return array
 685       */
 686  	protected function get_sortable_columns() {
 687          return array(
 688              'title'    => 'title',
 689              'parent'   => 'parent',
 690              'comments' => 'comment_count',
 691              'date'     => array( 'date', true ),
 692          );
 693      }
 694  
 695      /**
 696       * @global WP_Query $wp_query
 697       * @global int $per_page
 698       * @param array $posts
 699       * @param int $level
 700       */
 701  	public function display_rows( $posts = array(), $level = 0 ) {
 702          global $wp_query, $per_page;
 703  
 704          if ( empty( $posts ) ) {
 705              $posts = $wp_query->posts;
 706          }
 707  
 708          add_filter( 'the_title', 'esc_html' );
 709  
 710          if ( $this->hierarchical_display ) {
 711              $this->_display_rows_hierarchical( $posts, $this->get_pagenum(), $per_page );
 712          } else {
 713              $this->_display_rows( $posts, $level );
 714          }
 715      }
 716  
 717      /**
 718       * @param array $posts
 719       * @param int $level
 720       */
 721  	private function _display_rows( $posts, $level = 0 ) {
 722          $post_type = $this->screen->post_type;
 723  
 724          // Create array of post IDs.
 725          $post_ids = array();
 726  
 727          foreach ( $posts as $a_post ) {
 728              $post_ids[] = $a_post->ID;
 729          }
 730  
 731          if ( post_type_supports( $post_type, 'comments' ) ) {
 732              $this->comment_pending_count = get_pending_comments_num( $post_ids );
 733          }
 734  
 735          foreach ( $posts as $post ) {
 736              $this->single_row( $post, $level );
 737          }
 738      }
 739  
 740      /**
 741       * @global wpdb    $wpdb
 742       * @global WP_Post $post
 743       * @param array $pages
 744       * @param int $pagenum
 745       * @param int $per_page
 746       */
 747  	private function _display_rows_hierarchical( $pages, $pagenum = 1, $per_page = 20 ) {
 748          global $wpdb;
 749  
 750          $level = 0;
 751  
 752          if ( ! $pages ) {
 753              $pages = get_pages( array( 'sort_column' => 'menu_order' ) );
 754  
 755              if ( ! $pages ) {
 756                  return;
 757              }
 758          }
 759  
 760          /*
 761           * Arrange pages into two parts: top level pages and children_pages
 762           * children_pages is two dimensional array, eg.
 763           * children_pages[10][] contains all sub-pages whose parent is 10.
 764           * It only takes O( N ) to arrange this and it takes O( 1 ) for subsequent lookup operations
 765           * If searching, ignore hierarchy and treat everything as top level
 766           */
 767          if ( empty( $_REQUEST['s'] ) ) {
 768  
 769              $top_level_pages = array();
 770              $children_pages  = array();
 771  
 772              foreach ( $pages as $page ) {
 773  
 774                  // Catch and repair bad pages.
 775                  if ( $page->post_parent == $page->ID ) {
 776                      $page->post_parent = 0;
 777                      $wpdb->update( $wpdb->posts, array( 'post_parent' => 0 ), array( 'ID' => $page->ID ) );
 778                      clean_post_cache( $page );
 779                  }
 780  
 781                  if ( 0 == $page->post_parent ) {
 782                      $top_level_pages[] = $page;
 783                  } else {
 784                      $children_pages[ $page->post_parent ][] = $page;
 785                  }
 786              }
 787  
 788              $pages = &$top_level_pages;
 789          }
 790  
 791          $count      = 0;
 792          $start      = ( $pagenum - 1 ) * $per_page;
 793          $end        = $start + $per_page;
 794          $to_display = array();
 795  
 796          foreach ( $pages as $page ) {
 797              if ( $count >= $end ) {
 798                  break;
 799              }
 800  
 801              if ( $count >= $start ) {
 802                  $to_display[ $page->ID ] = $level;
 803              }
 804  
 805              $count++;
 806  
 807              if ( isset( $children_pages ) ) {
 808                  $this->_page_rows( $children_pages, $count, $page->ID, $level + 1, $pagenum, $per_page, $to_display );
 809              }
 810          }
 811  
 812          // If it is the last pagenum and there are orphaned pages, display them with paging as well.
 813          if ( isset( $children_pages ) && $count < $end ) {
 814              foreach ( $children_pages as $orphans ) {
 815                  foreach ( $orphans as $op ) {
 816                      if ( $count >= $end ) {
 817                          break;
 818                      }
 819  
 820                      if ( $count >= $start ) {
 821                          $to_display[ $op->ID ] = 0;
 822                      }
 823  
 824                      $count++;
 825                  }
 826              }
 827          }
 828  
 829          $ids = array_keys( $to_display );
 830          _prime_post_caches( $ids );
 831  
 832          if ( ! isset( $GLOBALS['post'] ) ) {
 833              $GLOBALS['post'] = reset( $ids );
 834          }
 835  
 836          foreach ( $to_display as $page_id => $level ) {
 837              echo "\t";
 838              $this->single_row( $page_id, $level );
 839          }
 840      }
 841  
 842      /**
 843       * Given a top level page ID, display the nested hierarchy of sub-pages
 844       * together with paging support
 845       *
 846       * @since 3.1.0 (Standalone function exists since 2.6.0)
 847       * @since 4.2.0 Added the `$to_display` parameter.
 848       *
 849       * @param array $children_pages
 850       * @param int $count
 851       * @param int $parent
 852       * @param int $level
 853       * @param int $pagenum
 854       * @param int $per_page
 855       * @param array $to_display List of pages to be displayed. Passed by reference.
 856       */
 857  	private function _page_rows( &$children_pages, &$count, $parent, $level, $pagenum, $per_page, &$to_display ) {
 858          if ( ! isset( $children_pages[ $parent ] ) ) {
 859              return;
 860          }
 861  
 862          $start = ( $pagenum - 1 ) * $per_page;
 863          $end   = $start + $per_page;
 864  
 865          foreach ( $children_pages[ $parent ] as $page ) {
 866              if ( $count >= $end ) {
 867                  break;
 868              }
 869  
 870              // If the page starts in a subtree, print the parents.
 871              if ( $count == $start && $page->post_parent > 0 ) {
 872                  $my_parents = array();
 873                  $my_parent  = $page->post_parent;
 874                  while ( $my_parent ) {
 875                      // Get the ID from the list or the attribute if my_parent is an object
 876                      $parent_id = $my_parent;
 877                      if ( is_object( $my_parent ) ) {
 878                          $parent_id = $my_parent->ID;
 879                      }
 880  
 881                      $my_parent    = get_post( $parent_id );
 882                      $my_parents[] = $my_parent;
 883                      if ( ! $my_parent->post_parent ) {
 884                          break;
 885                      }
 886                      $my_parent = $my_parent->post_parent;
 887                  }
 888                  $num_parents = count( $my_parents );
 889                  while ( $my_parent = array_pop( $my_parents ) ) {
 890                      $to_display[ $my_parent->ID ] = $level - $num_parents;
 891                      $num_parents--;
 892                  }
 893              }
 894  
 895              if ( $count >= $start ) {
 896                  $to_display[ $page->ID ] = $level;
 897              }
 898  
 899              $count++;
 900  
 901              $this->_page_rows( $children_pages, $count, $page->ID, $level + 1, $pagenum, $per_page, $to_display );
 902          }
 903  
 904          unset( $children_pages[ $parent ] ); //required in order to keep track of orphans
 905      }
 906  
 907      /**
 908       * Handles the checkbox column output.
 909       *
 910       * @since 4.3.0
 911       *
 912       * @param WP_Post $post The current WP_Post object.
 913       */
 914  	public function column_cb( $post ) {
 915          if ( current_user_can( 'edit_post', $post->ID ) ) :
 916              ?>
 917              <label class="screen-reader-text" for="cb-select-<?php the_ID(); ?>">
 918                                                                                  <?php
 919                                                                                  printf( __( 'Select %s' ), _draft_or_post_title() );
 920                                                                                  ?>
 921              </label>
 922              <input id="cb-select-<?php the_ID(); ?>" type="checkbox" name="post[]" value="<?php the_ID(); ?>" />
 923              <div class="locked-indicator">
 924                  <span class="locked-indicator-icon" aria-hidden="true"></span>
 925                  <span class="screen-reader-text">
 926                  <?php
 927                  printf(
 928                      /* translators: %s: post title */
 929                      __( '&#8220;%s&#8221; is locked' ),
 930                      _draft_or_post_title()
 931                  );
 932                  ?>
 933                  </span>
 934              </div>
 935              <?php
 936          endif;
 937      }
 938  
 939      /**
 940       * @since 4.3.0
 941       *
 942       * @param WP_Post $post
 943       * @param string  $classes
 944       * @param string  $data
 945       * @param string  $primary
 946       */
 947  	protected function _column_title( $post, $classes, $data, $primary ) {
 948          echo '<td class="' . $classes . ' page-title" ', $data, '>';
 949          echo $this->column_title( $post );
 950          echo $this->handle_row_actions( $post, 'title', $primary );
 951          echo '</td>';
 952      }
 953  
 954      /**
 955       * Handles the title column output.
 956       *
 957       * @since 4.3.0
 958       *
 959       * @global string $mode List table view mode.
 960       *
 961       * @param WP_Post $post The current WP_Post object.
 962       */
 963  	public function column_title( $post ) {
 964          global $mode;
 965  
 966          if ( $this->hierarchical_display ) {
 967              if ( 0 === $this->current_level && (int) $post->post_parent > 0 ) {
 968                  // Sent level 0 by accident, by default, or because we don't know the actual level.
 969                  $find_main_page = (int) $post->post_parent;
 970                  while ( $find_main_page > 0 ) {
 971                      $parent = get_post( $find_main_page );
 972  
 973                      if ( is_null( $parent ) ) {
 974                          break;
 975                      }
 976  
 977                      $this->current_level++;
 978                      $find_main_page = (int) $parent->post_parent;
 979  
 980                      if ( ! isset( $parent_name ) ) {
 981                          /** This filter is documented in wp-includes/post-template.php */
 982                          $parent_name = apply_filters( 'the_title', $parent->post_title, $parent->ID );
 983                      }
 984                  }
 985              }
 986          }
 987  
 988          $can_edit_post = current_user_can( 'edit_post', $post->ID );
 989  
 990          if ( $can_edit_post && $post->post_status != 'trash' ) {
 991              $lock_holder = wp_check_post_lock( $post->ID );
 992  
 993              if ( $lock_holder ) {
 994                  $lock_holder   = get_userdata( $lock_holder );
 995                  $locked_avatar = get_avatar( $lock_holder->ID, 18 );
 996                  $locked_text   = esc_html( sprintf( __( '%s is currently editing' ), $lock_holder->display_name ) );
 997              } else {
 998                  $locked_avatar = $locked_text = '';
 999              }
1000  
1001              echo '<div class="locked-info"><span class="locked-avatar">' . $locked_avatar . '</span> <span class="locked-text">' . $locked_text . "</span></div>\n";
1002          }
1003  
1004          $pad = str_repeat( '&#8212; ', $this->current_level );
1005          echo '<strong>';
1006  
1007          $title = _draft_or_post_title();
1008  
1009          if ( $can_edit_post && $post->post_status != 'trash' ) {
1010              printf(
1011                  '<a class="row-title" href="%s" aria-label="%s">%s%s</a>',
1012                  get_edit_post_link( $post->ID ),
1013                  /* translators: %s: post title */
1014                  esc_attr( sprintf( __( '&#8220;%s&#8221; (Edit)' ), $title ) ),
1015                  $pad,
1016                  $title
1017              );
1018          } else {
1019              printf(
1020                  '<span>%s%s</span>',
1021                  $pad,
1022                  $title
1023              );
1024          }
1025          _post_states( $post );
1026  
1027          if ( isset( $parent_name ) ) {
1028              $post_type_object = get_post_type_object( $post->post_type );
1029              echo ' | ' . $post_type_object->labels->parent_item_colon . ' ' . esc_html( $parent_name );
1030          }
1031          echo "</strong>\n";
1032  
1033          if ( ! is_post_type_hierarchical( $this->screen->post_type ) && 'excerpt' === $mode && current_user_can( 'read_post', $post->ID ) ) {
1034              if ( post_password_required( $post ) ) {
1035                  echo '<span class="protected-post-excerpt">' . esc_html( get_the_excerpt() ) . '</span>';
1036              } else {
1037                  echo esc_html( get_the_excerpt() );
1038              }
1039          }
1040  
1041          get_inline_data( $post );
1042      }
1043  
1044      /**
1045       * Handles the post date column output.
1046       *
1047       * @since 4.3.0
1048       *
1049       * @global string $mode List table view mode.
1050       *
1051       * @param WP_Post $post The current WP_Post object.
1052       */
1053  	public function column_date( $post ) {
1054          global $mode;
1055  
1056          if ( '0000-00-00 00:00:00' === $post->post_date ) {
1057              $t_time    = $h_time = __( 'Unpublished' );
1058              $time_diff = 0;
1059          } else {
1060              $t_time = get_the_time( __( 'Y/m/d g:i:s a' ) );
1061              $m_time = $post->post_date;
1062              $time   = get_post_time( 'G', true, $post );
1063  
1064              $time_diff = time() - $time;
1065  
1066              if ( $time_diff > 0 && $time_diff < DAY_IN_SECONDS ) {
1067                  $h_time = sprintf( __( '%s ago' ), human_time_diff( $time ) );
1068              } else {
1069                  $h_time = mysql2date( __( 'Y/m/d' ), $m_time );
1070              }
1071          }
1072  
1073          if ( 'publish' === $post->post_status ) {
1074              $status = __( 'Published' );
1075          } elseif ( 'future' === $post->post_status ) {
1076              if ( $time_diff > 0 ) {
1077                  $status = '<strong class="error-message">' . __( 'Missed schedule' ) . '</strong>';
1078              } else {
1079                  $status = __( 'Scheduled' );
1080              }
1081          } else {
1082              $status = __( 'Last Modified' );
1083          }
1084  
1085          /**
1086           * Filters the status text of the post.
1087           *
1088           * @since 4.8.0
1089           *
1090           * @param string  $status      The status text.
1091           * @param WP_Post $post        Post object.
1092           * @param string  $column_name The column name.
1093           * @param string  $mode        The list display mode ('excerpt' or 'list').
1094           */
1095          $status = apply_filters( 'post_date_column_status', $status, $post, 'date', $mode );
1096  
1097          if ( $status ) {
1098              echo $status . '<br />';
1099          }
1100  
1101          if ( 'excerpt' === $mode ) {
1102              /**
1103               * Filters the published time of the post.
1104               *
1105               * If `$mode` equals 'excerpt', the published time and date are both displayed.
1106               * If `$mode` equals 'list' (default), the publish date is displayed, with the
1107               * time and date together available as an abbreviation definition.
1108               *
1109               * @since 2.5.1
1110               *
1111               * @param string  $t_time      The published time.
1112               * @param WP_Post $post        Post object.
1113               * @param string  $column_name The column name.
1114               * @param string  $mode        The list display mode ('excerpt' or 'list').
1115               */
1116              echo apply_filters( 'post_date_column_time', $t_time, $post, 'date', $mode );
1117          } else {
1118  
1119              /** This filter is documented in wp-admin/includes/class-wp-posts-list-table.php */
1120              echo '<abbr title="' . $t_time . '">' . apply_filters( 'post_date_column_time', $h_time, $post, 'date', $mode ) . '</abbr>';
1121          }
1122      }
1123  
1124      /**
1125       * Handles the comments column output.
1126       *
1127       * @since 4.3.0
1128       *
1129       * @param WP_Post $post The current WP_Post object.
1130       */
1131  	public function column_comments( $post ) {
1132          ?>
1133          <div class="post-com-count-wrapper">
1134          <?php
1135              $pending_comments = isset( $this->comment_pending_count[ $post->ID ] ) ? $this->comment_pending_count[ $post->ID ] : 0;
1136  
1137              $this->comments_bubble( $post->ID, $pending_comments );
1138          ?>
1139          </div>
1140          <?php
1141      }
1142  
1143      /**
1144       * Handles the post author column output.
1145       *
1146       * @since 4.3.0
1147       *
1148       * @param WP_Post $post The current WP_Post object.
1149       */
1150  	public function column_author( $post ) {
1151          $args = array(
1152              'post_type' => $post->post_type,
1153              'author'    => get_the_author_meta( 'ID' ),
1154          );
1155          echo $this->get_edit_link( $args, get_the_author() );
1156      }
1157  
1158      /**
1159       * Handles the default column output.
1160       *
1161       * @since 4.3.0
1162       *
1163       * @param WP_Post $post        The current WP_Post object.
1164       * @param string  $column_name The current column name.
1165       */
1166  	public function column_default( $post, $column_name ) {
1167          if ( 'categories' === $column_name ) {
1168              $taxonomy = 'category';
1169          } elseif ( 'tags' === $column_name ) {
1170              $taxonomy = 'post_tag';
1171          } elseif ( 0 === strpos( $column_name, 'taxonomy-' ) ) {
1172              $taxonomy = substr( $column_name, 9 );
1173          } else {
1174              $taxonomy = false;
1175          }
1176          if ( $taxonomy ) {
1177              $taxonomy_object = get_taxonomy( $taxonomy );
1178              $terms           = get_the_terms( $post->ID, $taxonomy );
1179              if ( is_array( $terms ) ) {
1180                  $term_links = array();
1181                  foreach ( $terms as $t ) {
1182                      $posts_in_term_qv = array();
1183                      if ( 'post' != $post->post_type ) {
1184                          $posts_in_term_qv['post_type'] = $post->post_type;
1185                      }
1186                      if ( $taxonomy_object->query_var ) {
1187                          $posts_in_term_qv[ $taxonomy_object->query_var ] = $t->slug;
1188                      } else {
1189                          $posts_in_term_qv['taxonomy'] = $taxonomy;
1190                          $posts_in_term_qv['term']     = $t->slug;
1191                      }
1192  
1193                      $label = esc_html( sanitize_term_field( 'name', $t->name, $t->term_id, $taxonomy, 'display' ) );
1194  
1195                      $term_links[] = $this->get_edit_link( $posts_in_term_qv, $label );
1196                  }
1197  
1198                  /**
1199                   * Filters the links in `$taxonomy` column of edit.php.
1200                   *
1201                   * @since 5.2.0
1202                   *
1203                   * @param array  $term_links List of links to edit.php, filtered by the taxonomy term.
1204                   * @param string $taxonomy   Taxonomy name.
1205                   * @param array  $terms      Array of terms appearing in the post row.
1206                   */
1207                  $term_links = apply_filters( 'post_column_taxonomy_links', $term_links, $taxonomy, $terms );
1208  
1209                  /* translators: used between list items, there is a space after the comma */
1210                  echo join( __( ', ' ), $term_links );
1211              } else {
1212                  echo '<span aria-hidden="true">&#8212;</span><span class="screen-reader-text">' . $taxonomy_object->labels->no_terms . '</span>';
1213              }
1214              return;
1215          }
1216  
1217          if ( is_post_type_hierarchical( $post->post_type ) ) {
1218  
1219              /**
1220               * Fires in each custom column on the Posts list table.
1221               *
1222               * This hook only fires if the current post type is hierarchical,
1223               * such as pages.
1224               *
1225               * @since 2.5.0
1226               *
1227               * @param string $column_name The name of the column to display.
1228               * @param int    $post_id     The current post ID.
1229               */
1230              do_action( 'manage_pages_custom_column', $column_name, $post->ID );
1231          } else {
1232  
1233              /**
1234               * Fires in each custom column in the Posts list table.
1235               *
1236               * This hook only fires if the current post type is non-hierarchical,
1237               * such as posts.
1238               *
1239               * @since 1.5.0
1240               *
1241               * @param string $column_name The name of the column to display.
1242               * @param int    $post_id     The current post ID.
1243               */
1244              do_action( 'manage_posts_custom_column', $column_name, $post->ID );
1245          }
1246  
1247          /**
1248           * Fires for each custom column of a specific post type in the Posts list table.
1249           *
1250           * The dynamic portion of the hook name, `$post->post_type`, refers to the post type.
1251           *
1252           * @since 3.1.0
1253           *
1254           * @param string $column_name The name of the column to display.
1255           * @param int    $post_id     The current post ID.
1256           */
1257          do_action( "manage_{$post->post_type}_posts_custom_column", $column_name, $post->ID );
1258      }
1259  
1260      /**
1261       * @global WP_Post $post
1262       *
1263       * @param int|WP_Post $post
1264       * @param int         $level
1265       */
1266  	public function single_row( $post, $level = 0 ) {
1267          $global_post = get_post();
1268  
1269          $post                = get_post( $post );
1270          $this->current_level = $level;
1271  
1272          $GLOBALS['post'] = $post;
1273          setup_postdata( $post );
1274  
1275          $classes = 'iedit author-' . ( get_current_user_id() == $post->post_author ? 'self' : 'other' );
1276  
1277          $lock_holder = wp_check_post_lock( $post->ID );
1278          if ( $lock_holder ) {
1279              $classes .= ' wp-locked';
1280          }
1281  
1282          if ( $post->post_parent ) {
1283              $count    = count( get_post_ancestors( $post->ID ) );
1284              $classes .= ' level-' . $count;
1285          } else {
1286              $classes .= ' level-0';
1287          }
1288          ?>
1289          <tr id="post-<?php echo $post->ID; ?>" class="<?php echo implode( ' ', get_post_class( $classes, $post->ID ) ); ?>">
1290              <?php $this->single_row_columns( $post ); ?>
1291          </tr>
1292          <?php
1293          $GLOBALS['post'] = $global_post;
1294      }
1295  
1296      /**
1297       * Gets the name of the default primary column.
1298       *
1299       * @since 4.3.0
1300       *
1301       * @return string Name of the default primary column, in this case, 'title'.
1302       */
1303  	protected function get_default_primary_column_name() {
1304          return 'title';
1305      }
1306  
1307      /**
1308       * Generates and displays row action links.
1309       *
1310       * @since 4.3.0
1311       *
1312       * @param object $post        Post being acted upon.
1313       * @param string $column_name Current column name.
1314       * @param string $primary     Primary column name.
1315       * @return string Row actions output for posts.
1316       */
1317  	protected function handle_row_actions( $post, $column_name, $primary ) {
1318          if ( $primary !== $column_name ) {
1319              return '';
1320          }
1321  
1322          $post_type_object = get_post_type_object( $post->post_type );
1323          $can_edit_post    = current_user_can( 'edit_post', $post->ID );
1324          $actions          = array();
1325          $title            = _draft_or_post_title();
1326  
1327          if ( $can_edit_post && 'trash' != $post->post_status ) {
1328              $actions['edit'] = sprintf(
1329                  '<a href="%s" aria-label="%s">%s</a>',
1330                  get_edit_post_link( $post->ID ),
1331                  /* translators: %s: post title */
1332                  esc_attr( sprintf( __( 'Edit &#8220;%s&#8221;' ), $title ) ),
1333                  __( 'Edit' )
1334              );
1335  
1336              if ( 'wp_block' !== $post->post_type ) {
1337                  $actions['inline hide-if-no-js'] = sprintf(
1338                      '<button type="button" class="button-link editinline" aria-label="%s" aria-expanded="false">%s</button>',
1339                      /* translators: %s: post title */
1340                      esc_attr( sprintf( __( 'Quick edit &#8220;%s&#8221; inline' ), $title ) ),
1341                      __( 'Quick&nbsp;Edit' )
1342                  );
1343              }
1344          }
1345  
1346          if ( current_user_can( 'delete_post', $post->ID ) ) {
1347              if ( 'trash' === $post->post_status ) {
1348                  $actions['untrash'] = sprintf(
1349                      '<a href="%s" aria-label="%s">%s</a>',
1350                      wp_nonce_url( admin_url( sprintf( $post_type_object->_edit_link . '&amp;action=untrash', $post->ID ) ), 'untrash-post_' . $post->ID ),
1351                      /* translators: %s: post title */
1352                      esc_attr( sprintf( __( 'Restore &#8220;%s&#8221; from the Trash' ), $title ) ),
1353                      __( 'Restore' )
1354                  );
1355              } elseif ( EMPTY_TRASH_DAYS ) {
1356                  $actions['trash'] = sprintf(
1357                      '<a href="%s" class="submitdelete" aria-label="%s">%s</a>',
1358                      get_delete_post_link( $post->ID ),
1359                      /* translators: %s: post title */
1360                      esc_attr( sprintf( __( 'Move &#8220;%s&#8221; to the Trash' ), $title ) ),
1361                      _x( 'Trash', 'verb' )
1362                  );
1363              }
1364              if ( 'trash' === $post->post_status || ! EMPTY_TRASH_DAYS ) {
1365                  $actions['delete'] = sprintf(
1366                      '<a href="%s" class="submitdelete" aria-label="%s">%s</a>',
1367                      get_delete_post_link( $post->ID, '', true ),
1368                      /* translators: %s: post title */
1369                      esc_attr( sprintf( __( 'Delete &#8220;%s&#8221; permanently' ), $title ) ),
1370                      __( 'Delete Permanently' )
1371                  );
1372              }
1373          }
1374  
1375          if ( is_post_type_viewable( $post_type_object ) ) {
1376              if ( in_array( $post->post_status, array( 'pending', 'draft', 'future' ) ) ) {
1377                  if ( $can_edit_post ) {
1378                      $preview_link    = get_preview_post_link( $post );
1379                      $actions['view'] = sprintf(
1380                          '<a href="%s" rel="bookmark" aria-label="%s">%s</a>',
1381                          esc_url( $preview_link ),
1382                          /* translators: %s: post title */
1383                          esc_attr( sprintf( __( 'Preview &#8220;%s&#8221;' ), $title ) ),
1384                          __( 'Preview' )
1385                      );
1386                  }
1387              } elseif ( 'trash' != $post->post_status ) {
1388                  $actions['view'] = sprintf(
1389                      '<a href="%s" rel="bookmark" aria-label="%s">%s</a>',
1390                      get_permalink( $post->ID ),
1391                      /* translators: %s: post title */
1392                      esc_attr( sprintf( __( 'View &#8220;%s&#8221;' ), $title ) ),
1393                      __( 'View' )
1394                  );
1395              }
1396          }
1397  
1398          if ( 'wp_block' === $post->post_type ) {
1399              $actions['export'] = sprintf(
1400                  '<button type="button" class="wp-list-reusable-blocks__export button-link" data-id="%s" aria-label="%s">%s</button>',
1401                  $post->ID,
1402                  /* translators: %s: post title */
1403                  esc_attr( sprintf( __( 'Export &#8220;%s&#8221; as JSON' ), $title ) ),
1404                  __( 'Export as JSON' )
1405              );
1406          }
1407  
1408          if ( is_post_type_hierarchical( $post->post_type ) ) {
1409  
1410              /**
1411               * Filters the array of row action links on the Pages list table.
1412               *
1413               * The filter is evaluated only for hierarchical post types.
1414               *
1415               * @since 2.8.0
1416               *
1417               * @param string[] $actions An array of row action links. Defaults are
1418               *                          'Edit', 'Quick Edit', 'Restore', 'Trash',
1419               *                          'Delete Permanently', 'Preview', and 'View'.
1420               * @param WP_Post  $post    The post object.
1421               */
1422              $actions = apply_filters( 'page_row_actions', $actions, $post );
1423          } else {
1424  
1425              /**
1426               * Filters the array of row action links on the Posts list table.
1427               *
1428               * The filter is evaluated only for non-hierarchical post types.
1429               *
1430               * @since 2.8.0
1431               *
1432               * @param string[] $actions An array of row action links. Defaults are
1433               *                          'Edit', 'Quick Edit', 'Restore', 'Trash',
1434               *                          'Delete Permanently', 'Preview', and 'View'.
1435               * @param WP_Post  $post    The post object.
1436               */
1437              $actions = apply_filters( 'post_row_actions', $actions, $post );
1438          }
1439  
1440          return $this->row_actions( $actions );
1441      }
1442  
1443      /**
1444       * Outputs the hidden row displayed when inline editing
1445       *
1446       * @since 3.1.0
1447       *
1448       * @global string $mode List table view mode.
1449       */
1450  	public function inline_edit() {
1451          global $mode;
1452  
1453          $screen = $this->screen;
1454  
1455          $post             = get_default_post_to_edit( $screen->post_type );
1456          $post_type_object = get_post_type_object( $screen->post_type );
1457  
1458          $taxonomy_names          = get_object_taxonomies( $screen->post_type );
1459          $hierarchical_taxonomies = array();
1460          $flat_taxonomies         = array();
1461          foreach ( $taxonomy_names as $taxonomy_name ) {
1462  
1463              $taxonomy = get_taxonomy( $taxonomy_name );
1464  
1465              $show_in_quick_edit = $taxonomy->show_in_quick_edit;
1466  
1467              /**
1468               * Filters whether the current taxonomy should be shown in the Quick Edit panel.
1469               *
1470               * @since 4.2.0
1471               *
1472               * @param bool   $show_in_quick_edit Whether to show the current taxonomy in Quick Edit.
1473               * @param string $taxonomy_name      Taxonomy name.
1474               * @param string $post_type          Post type of current Quick Edit post.
1475               */
1476              if ( ! apply_filters( 'quick_edit_show_taxonomy', $show_in_quick_edit, $taxonomy_name, $screen->post_type ) ) {
1477                  continue;
1478              }
1479  
1480              if ( $taxonomy->hierarchical ) {
1481                  $hierarchical_taxonomies[] = $taxonomy;
1482              } else {
1483                  $flat_taxonomies[] = $taxonomy;
1484              }
1485          }
1486  
1487          $m            = ( isset( $mode ) && 'excerpt' === $mode ) ? 'excerpt' : 'list';
1488          $can_publish  = current_user_can( $post_type_object->cap->publish_posts );
1489          $core_columns = array(
1490              'cb'         => true,
1491              'date'       => true,
1492              'title'      => true,
1493              'categories' => true,
1494              'tags'       => true,
1495              'comments'   => true,
1496              'author'     => true,
1497          );
1498  
1499          ?>
1500  
1501      <form method="get"><table style="display: none"><tbody id="inlineedit">
1502          <?php
1503          $hclass              = count( $hierarchical_taxonomies ) ? 'post' : 'page';
1504          $inline_edit_classes = "inline-edit-row inline-edit-row-$hclass";
1505          $bulk_edit_classes   = "bulk-edit-row bulk-edit-row-$hclass bulk-edit-{$screen->post_type}";
1506          $quick_edit_classes  = "quick-edit-row quick-edit-row-$hclass inline-edit-{$screen->post_type}";
1507  
1508          $bulk = 0;
1509          while ( $bulk < 2 ) {
1510              ?>
1511  
1512          <tr id="<?php echo $bulk ? 'bulk-edit' : 'inline-edit'; ?>" class="
1513                              <?php
1514                              echo $inline_edit_classes . ' ';
1515                              echo $bulk ? $bulk_edit_classes : $quick_edit_classes;
1516                              ?>
1517          " style="display: none"><td colspan="<?php echo $this->get_column_count(); ?>" class="colspanchange">
1518  
1519          <fieldset class="inline-edit-col-left">
1520              <legend class="inline-edit-legend"><?php echo $bulk ? __( 'Bulk Edit' ) : __( 'Quick Edit' ); ?></legend>
1521              <div class="inline-edit-col">
1522              <?php
1523  
1524              if ( post_type_supports( $screen->post_type, 'title' ) ) :
1525                  if ( $bulk ) :
1526                      ?>
1527              <div id="bulk-title-div">
1528                  <div id="bulk-titles"></div>
1529              </div>
1530  
1531              <?php else : // $bulk ?>
1532  
1533              <label>
1534                  <span class="title"><?php _e( 'Title' ); ?></span>
1535                  <span class="input-text-wrap"><input type="text" name="post_title" class="ptitle" value="" /></span>
1536              </label>
1537  
1538                  <?php if ( is_post_type_viewable( $screen->post_type ) ) : // is_post_type_viewable check ?>
1539  
1540              <label>
1541                  <span class="title"><?php _e( 'Slug' ); ?></span>
1542                  <span class="input-text-wrap"><input type="text" name="post_name" value="" /></span>
1543              </label>
1544  
1545                      <?php
1546      endif; // is_post_type_viewable check
1547      endif; // $bulk
1548      endif; // post_type_supports title
1549              ?>
1550  
1551              <?php if ( ! $bulk ) : ?>
1552              <fieldset class="inline-edit-date">
1553              <legend><span class="title"><?php _e( 'Date' ); ?></span></legend>
1554                  <?php touch_time( 1, 1, 0, 1 ); ?>
1555              </fieldset>
1556              <br class="clear" />
1557                  <?php
1558      endif; // $bulk
1559  
1560              if ( post_type_supports( $screen->post_type, 'author' ) ) :
1561                  $authors_dropdown = '';
1562  
1563                  if ( current_user_can( $post_type_object->cap->edit_others_posts ) ) :
1564                      $users_opt = array(
1565                          'hide_if_only_one_author' => false,
1566                          'who'                     => 'authors',
1567                          'name'                    => 'post_author',
1568                          'class'                   => 'authors',
1569                          'multi'                   => 1,
1570                          'echo'                    => 0,
1571                          'show'                    => 'display_name_with_login',
1572                      );
1573                      if ( $bulk ) {
1574                          $users_opt['show_option_none'] = __( '&mdash; No Change &mdash;' );
1575                      }
1576  
1577                      if ( $authors = wp_dropdown_users( $users_opt ) ) :
1578                          $authors_dropdown  = '<label class="inline-edit-author">';
1579                          $authors_dropdown .= '<span class="title">' . __( 'Author' ) . '</span>';
1580                          $authors_dropdown .= $authors;
1581                          $authors_dropdown .= '</label>';
1582                      endif;
1583                  endif; // authors
1584                  ?>
1585  
1586                  <?php
1587                  if ( ! $bulk ) {
1588                      echo $authors_dropdown;}
1589      endif; // post_type_supports author
1590  
1591              if ( ! $bulk && $can_publish ) :
1592                  ?>
1593  
1594          <div class="inline-edit-group wp-clearfix">
1595              <label class="alignleft">
1596                  <span class="title"><?php _e( 'Password' ); ?></span>
1597                  <span class="input-text-wrap"><input type="text" name="post_password" class="inline-edit-password-input" value="" /></span>
1598              </label>
1599  
1600              <em class="alignleft inline-edit-or">
1601                  <?php
1602                  /* translators: Between password field and private checkbox on post quick edit interface */
1603                  _e( '&ndash;OR&ndash;' );
1604                  ?>
1605                  </em>
1606                  <label class="alignleft inline-edit-private">
1607                  <input type="checkbox" name="keep_private" value="private" />
1608                  <span class="checkbox-title"><?php _e( 'Private' ); ?></span>
1609                  </label>
1610              </div>
1611  
1612                  <?php endif; ?>
1613  
1614          </div></fieldset>
1615  
1616              <?php if ( count( $hierarchical_taxonomies ) && ! $bulk ) : ?>
1617  
1618          <fieldset class="inline-edit-col-center inline-edit-categories"><div class="inline-edit-col">
1619  
1620                  <?php foreach ( $hierarchical_taxonomies as $taxonomy ) : ?>
1621  
1622              <span class="title inline-edit-categories-label"><?php echo esc_html( $taxonomy->labels->name ); ?></span>
1623              <input type="hidden" name="<?php echo ( $taxonomy->name === 'category' ) ? 'post_category[]' : 'tax_input[' . esc_attr( $taxonomy->name ) . '][]'; ?>" value="0" />
1624              <ul class="cat-checklist <?php echo esc_attr( $taxonomy->name ); ?>-checklist">
1625                      <?php wp_terms_checklist( null, array( 'taxonomy' => $taxonomy->name ) ); ?>
1626              </ul>
1627  
1628      <?php endforeach; //$hierarchical_taxonomies as $taxonomy ?>
1629  
1630          </div></fieldset>
1631  
1632      <?php endif; // count( $hierarchical_taxonomies ) && !$bulk ?>
1633  
1634          <fieldset class="inline-edit-col-right"><div class="inline-edit-col">
1635  
1636              <?php
1637              if ( post_type_supports( $screen->post_type, 'author' ) && $bulk ) {
1638                  echo $authors_dropdown;
1639              }
1640  
1641              if ( post_type_supports( $screen->post_type, 'page-attributes' ) ) :
1642  
1643                  if ( $post_type_object->hierarchical ) :
1644                      ?>
1645          <label>
1646              <span class="title"><?php _e( 'Parent' ); ?></span>
1647                      <?php
1648                      $dropdown_args = array(
1649                          'post_type'         => $post_type_object->name,
1650                          'selected'          => $post->post_parent,
1651                          'name'              => 'post_parent',
1652                          'show_option_none'  => __( 'Main Page (no parent)' ),
1653                          'option_none_value' => 0,
1654                          'sort_column'       => 'menu_order, post_title',
1655                      );
1656  
1657                      if ( $bulk ) {
1658                          $dropdown_args['show_option_no_change'] = __( '&mdash; No Change &mdash;' );
1659                      }
1660  
1661                      /**
1662                       * Filters the arguments used to generate the Quick Edit page-parent drop-down.
1663                       *
1664                       * @since 2.7.0
1665                       *
1666                       * @see wp_dropdown_pages()
1667                       *
1668                       * @param array $dropdown_args An array of arguments.
1669                       */
1670                      $dropdown_args = apply_filters( 'quick_edit_dropdown_pages_args', $dropdown_args );
1671  
1672                      wp_dropdown_pages( $dropdown_args );
1673                      ?>
1674          </label>
1675  
1676                      <?php
1677                  endif; // hierarchical
1678  
1679                  if ( ! $bulk ) :
1680                      ?>
1681  
1682              <label>
1683                  <span class="title"><?php _e( 'Order' ); ?></span>
1684                  <span class="input-text-wrap"><input type="text" name="menu_order" class="inline-edit-menu-order-input" value="<?php echo $post->menu_order; ?>" /></span>
1685              </label>
1686  
1687                      <?php
1688                  endif; // !$bulk
1689          endif; // page-attributes
1690              ?>
1691  
1692              <?php if ( 0 < count( get_page_templates( null, $screen->post_type ) ) ) : ?>
1693          <label>
1694              <span class="title"><?php _e( 'Template' ); ?></span>
1695              <select name="page_template">
1696                  <?php    if ( $bulk ) : ?>
1697                  <option value="-1"><?php _e( '&mdash; No Change &mdash;' ); ?></option>
1698                  <?php    endif; // $bulk ?>
1699                  <?php
1700                  /** This filter is documented in wp-admin/includes/meta-boxes.php */
1701                  $default_title = apply_filters( 'default_page_template_title', __( 'Default Template' ), 'quick-edit' );
1702                  ?>
1703                  <option value="default"><?php echo esc_html( $default_title ); ?></option>
1704                  <?php page_template_dropdown( '', $screen->post_type ); ?>
1705              </select>
1706          </label>
1707      <?php endif; ?>
1708  
1709              <?php if ( count( $flat_taxonomies ) && ! $bulk ) : ?>
1710  
1711                  <?php foreach ( $flat_taxonomies as $taxonomy ) : ?>
1712                      <?php
1713                      if ( current_user_can( $taxonomy->cap->assign_terms ) ) :
1714                          $taxonomy_name = esc_attr( $taxonomy->name );
1715  
1716                          ?>
1717              <label class="inline-edit-tags">
1718                  <span class="title"><?php echo esc_html( $taxonomy->labels->name ); ?></span>
1719                  <textarea data-wp-taxonomy="<?php echo $taxonomy_name; ?>" cols="22" rows="1" name="tax_input[<?php echo $taxonomy_name; ?>]" class="tax_input_<?php echo $taxonomy_name; ?>"></textarea>
1720              </label>
1721                      <?php endif; ?>
1722  
1723      <?php endforeach; //$flat_taxonomies as $taxonomy ?>
1724  
1725      <?php endif; // count( $flat_taxonomies ) && !$bulk ?>
1726  
1727              <?php
1728              if ( post_type_supports( $screen->post_type, 'comments' ) || post_type_supports( $screen->post_type, 'trackbacks' ) ) :
1729                  if ( $bulk ) :
1730                      ?>
1731  
1732              <div class="inline-edit-group wp-clearfix">
1733                      <?php if ( post_type_supports( $screen->post_type, 'comments' ) ) : ?>
1734              <label class="alignleft">
1735                  <span class="title"><?php _e( 'Comments' ); ?></span>
1736                  <select name="comment_status">
1737                      <option value=""><?php _e( '&mdash; No Change &mdash;' ); ?></option>
1738                      <option value="open"><?php _e( 'Allow' ); ?></option>
1739                      <option value="closed"><?php _e( 'Do not allow' ); ?></option>
1740                  </select>
1741              </label>
1742          <?php endif; if ( post_type_supports( $screen->post_type, 'trackbacks' ) ) : ?>
1743              <label class="alignright">
1744                  <span class="title"><?php _e( 'Pings' ); ?></span>
1745                  <select name="ping_status">
1746                      <option value=""><?php _e( '&mdash; No Change &mdash;' ); ?></option>
1747                      <option value="open"><?php _e( 'Allow' ); ?></option>
1748                      <option value="closed"><?php _e( 'Do not allow' ); ?></option>
1749                  </select>
1750              </label>
1751          <?php endif; ?>
1752              </div>
1753  
1754              <?php else : // $bulk ?>
1755  
1756              <div class="inline-edit-group wp-clearfix">
1757                  <?php if ( post_type_supports( $screen->post_type, 'comments' ) ) : ?>
1758                  <label class="alignleft">
1759                      <input type="checkbox" name="comment_status" value="open" />
1760                      <span class="checkbox-title"><?php _e( 'Allow Comments' ); ?></span>
1761                  </label>
1762              <?php endif; if ( post_type_supports( $screen->post_type, 'trackbacks' ) ) : ?>
1763                  <label class="alignleft">
1764                      <input type="checkbox" name="ping_status" value="open" />
1765                      <span class="checkbox-title"><?php _e( 'Allow Pings' ); ?></span>
1766                  </label>
1767              <?php endif; ?>
1768              </div>
1769  
1770                  <?php
1771      endif; // $bulk
1772      endif; // post_type_supports comments or pings
1773              ?>
1774  
1775              <div class="inline-edit-group wp-clearfix">
1776                  <label class="inline-edit-status alignleft">
1777                      <span class="title"><?php _e( 'Status' ); ?></span>
1778                      <select name="_status">
1779              <?php if ( $bulk ) : ?>
1780                          <option value="-1"><?php _e( '&mdash; No Change &mdash;' ); ?></option>
1781      <?php endif; // $bulk ?>
1782                      <?php if ( $can_publish ) : // Contributors only get "Unpublished" and "Pending Review" ?>
1783                          <option value="publish"><?php _e( 'Published' ); ?></option>
1784                          <option value="future"><?php _e( 'Scheduled' ); ?></option>
1785                          <?php if ( $bulk ) : ?>
1786                          <option value="private"><?php _e( 'Private' ); ?></option>
1787      <?php endif; // $bulk ?>
1788                      <?php endif; ?>
1789                          <option value="pending"><?php _e( 'Pending Review' ); ?></option>
1790                          <option value="draft"><?php _e( 'Draft' ); ?></option>
1791                      </select>
1792                  </label>
1793  
1794              <?php if ( 'post' === $screen->post_type && $can_publish && current_user_can( $post_type_object->cap->edit_others_posts ) ) : ?>
1795  
1796                  <?php    if ( $bulk ) : ?>
1797  
1798                  <label class="alignright">
1799                      <span class="title"><?php _e( 'Sticky' ); ?></span>
1800                      <select name="sticky">
1801                          <option value="-1"><?php _e( '&mdash; No Change &mdash;' ); ?></option>
1802                          <option value="sticky"><?php _e( 'Sticky' ); ?></option>
1803                          <option value="unsticky"><?php _e( 'Not Sticky' ); ?></option>
1804                      </select>
1805                  </label>
1806  
1807      <?php    else : // $bulk ?>
1808  
1809                  <label class="alignleft">
1810                      <input type="checkbox" name="sticky" value="sticky" />
1811                      <span class="checkbox-title"><?php _e( 'Make this post sticky' ); ?></span>
1812                  </label>
1813  
1814      <?php    endif; // $bulk ?>
1815  
1816      <?php endif; // 'post' && $can_publish && current_user_can( 'edit_others_cap' ) ?>
1817  
1818              </div>
1819  
1820              <?php
1821  
1822              if ( $bulk && current_theme_supports( 'post-formats' ) && post_type_supports( $screen->post_type, 'post-formats' ) ) {
1823                  $post_formats = get_theme_support( 'post-formats' );
1824  
1825                  ?>
1826          <label class="alignleft">
1827          <span class="title"><?php _ex( 'Format', 'post format' ); ?></span>
1828          <select name="post_format">
1829              <option value="-1"><?php _e( '&mdash; No Change &mdash;' ); ?></option>
1830              <option value="0"><?php echo get_post_format_string( 'standard' ); ?></option>
1831                  <?php
1832                  if ( is_array( $post_formats[0] ) ) {
1833                      foreach ( $post_formats[0] as $format ) {
1834                          ?>
1835                      <option value="<?php echo esc_attr( $format ); ?>"><?php echo esc_html( get_post_format_string( $format ) ); ?></option>
1836                          <?php
1837                      }
1838                  }
1839                  ?>
1840          </select></label>
1841                  <?php
1842  
1843              }
1844  
1845              ?>
1846  
1847          </div></fieldset>
1848  
1849              <?php
1850              list( $columns ) = $this->get_column_info();
1851  
1852              foreach ( $columns as $column_name => $column_display_name ) {
1853                  if ( isset( $core_columns[ $column_name ] ) ) {
1854                      continue;
1855                  }
1856  
1857                  if ( $bulk ) {
1858  
1859                      /**
1860                       * Fires once for each column in Bulk Edit mode.
1861                       *
1862                       * @since 2.7.0
1863                       *
1864                       * @param string  $column_name Name of the column to edit.
1865                       * @param WP_Post $post_type   The post type slug.
1866                       */
1867                      do_action( 'bulk_edit_custom_box', $column_name, $screen->post_type );
1868                  } else {
1869  
1870                      /**
1871                       * Fires once for each column in Quick Edit mode.
1872                       *
1873                       * @since 2.7.0
1874                       *
1875                       * @param string $column_name Name of the column to edit.
1876                       * @param string $post_type   The post type slug, or current screen name if this is a taxonomy list table.
1877                       * @param string taxonomy     The taxonomy name, if any.
1878                       */
1879                      do_action( 'quick_edit_custom_box', $column_name, $screen->post_type, '' );
1880                  }
1881              }
1882              ?>
1883          <div class="submit inline-edit-save">
1884              <button type="button" class="button cancel alignleft"><?php _e( 'Cancel' ); ?></button>
1885              <?php
1886              if ( ! $bulk ) {
1887                  wp_nonce_field( 'inlineeditnonce', '_inline_edit', false );
1888                  ?>
1889                  <button type="button" class="button button-primary save alignright"><?php _e( 'Update' ); ?></button>
1890                  <span class="spinner"></span>
1891                  <?php
1892              } else {
1893                  submit_button( __( 'Update' ), 'primary alignright', 'bulk_edit', false );
1894              }
1895              ?>
1896              <input type="hidden" name="post_view" value="<?php echo esc_attr( $m ); ?>" />
1897              <input type="hidden" name="screen" value="<?php echo esc_attr( $screen->id ); ?>" />
1898              <?php if ( ! $bulk && ! post_type_supports( $screen->post_type, 'author' ) ) { ?>
1899                  <input type="hidden" name="post_author" value="<?php echo esc_attr( $post->post_author ); ?>" />
1900              <?php } ?>
1901              <br class="clear" />
1902              <div class="notice notice-error notice-alt inline hidden">
1903                  <p class="error"></p>
1904              </div>
1905          </div>
1906          </td></tr>
1907              <?php
1908              $bulk++;
1909          }
1910          ?>
1911          </tbody></table></form>
1912          <?php
1913      }
1914  }


Generated: Mon Jun 24 08:20:01 2019 Cross-referenced by PHPXref 0.7