WP_Posts_List_Table

Core class used to implement displaying posts in a list table.

Defined (1)

The class is defined in the following location(s).

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