WP_Posts_List_Table   D
last analyzed

Complexity

Total Complexity 247

Size/Duplication

Total Lines 1757
Duplicated Lines 5.01 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
dl 88
loc 1757
rs 4
c 0
b 0
f 0
wmc 247
lcom 1
cbo 3

31 Methods

Rating   Name   Duplication   Size   Complexity  
D __construct() 0 31 10
A set_hierarchical_display() 0 3 1
A ajax_user_can() 0 3 1
C prepare_items() 6 51 15
A has_items() 0 3 1
A no_items() 0 6 3
B is_base_request() 0 12 5
A get_edit_link() 0 18 2
F get_views() 0 122 19
B get_bulk_actions() 0 22 6
B categories_dropdown() 0 29 3
C extra_tablenav() 0 51 7
A current_action() 0 6 3
A get_table_classes() 0 3 2
C get_columns() 10 82 9
A get_sortable_columns() 8 8 1
A display_rows() 0 14 3
A _display_rows() 0 12 3
D _display_rows_hierarchical() 0 89 19
C _page_rows() 4 46 11
A column_cb() 0 18 2
A _column_title() 0 6 1
D column_title() 0 86 17
C column_date() 0 70 9
A column_comments() 0 11 2
A column_author() 0 7 1
C column_default() 9 80 10
B single_row() 0 29 4
A get_default_primary_column_name() 0 3 1
D handle_row_actions() 24 112 14
F inline_edit() 27 423 62

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like WP_Posts_List_Table often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use WP_Posts_List_Table, and based on these observations, apply Extract Interface, too.

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
	 * @access protected
26
	 */
27
	protected $hierarchical_display;
28
29
	/**
30
	 * Holds the number of pending comments for each post.
31
	 *
32
	 * @since 3.1.0
33
	 * @var array
34
	 * @access protected
35
	 */
36
	protected $comment_pending_count;
37
38
	/**
39
	 * Holds the number of posts for this user.
40
	 *
41
	 * @since 3.1.0
42
	 * @var int
43
	 * @access private
44
	 */
45
	private $user_posts_count;
46
47
	/**
48
	 * Holds the number of posts which are sticky.
49
	 *
50
	 * @since 3.1.0
51
	 * @var int
52
	 * @access private
53
	 */
54
	private $sticky_posts_count = 0;
55
56
	private $is_trash;
57
58
	/**
59
	 * Current level for output.
60
	 *
61
	 * @since 4.3.0
62
	 * @access protected
63
	 * @var int
64
	 */
65
	protected $current_level = 0;
66
67
	/**
68
	 * Constructor.
69
	 *
70
	 * @since 3.1.0
71
	 * @access public
72
	 *
73
	 * @see WP_List_Table::__construct() for more information on default arguments.
74
	 *
75
	 * @global WP_Post_Type $post_type_object
76
	 * @global wpdb         $wpdb
77
	 *
78
	 * @param array $args An associative array of arguments.
79
	 */
80
	public function __construct( $args = array() ) {
81
		global $post_type_object, $wpdb;
82
83
		parent::__construct( array(
84
			'plural' => 'posts',
85
			'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
86
		) );
87
88
		$post_type        = $this->screen->post_type;
89
		$post_type_object = get_post_type_object( $post_type );
90
91
		$exclude_states   = get_post_stati( array(
92
			'show_in_admin_all_list' => false,
93
		) );
94
		$this->user_posts_count = intval( $wpdb->get_var( $wpdb->prepare( "
95
			SELECT COUNT( 1 )
96
			FROM $wpdb->posts
97
			WHERE post_type = %s
98
			AND post_status NOT IN ( '" . implode( "','", $exclude_states ) . "' )
99
			AND post_author = %d
100
		", $post_type, get_current_user_id() ) ) );
101
102
		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'] ) ) {
103
			$_GET['author'] = get_current_user_id();
104
		}
105
106
		if ( 'post' === $post_type && $sticky_posts = get_option( 'sticky_posts' ) ) {
107
			$sticky_posts = implode( ', ', array_map( 'absint', (array) $sticky_posts ) );
108
			$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 ) );
109
		}
110
	}
111
112
	/**
113
	 * Sets whether the table layout should be hierarchical or not.
114
	 *
115
	 * @since 4.2.0
116
	 *
117
	 * @param bool $display Whether the table layout should be hierarchical.
118
	 */
119
	public function set_hierarchical_display( $display ) {
120
		$this->hierarchical_display = $display;
121
	}
122
123
	/**
124
	 *
125
	 * @return bool
126
	 */
127
	public function ajax_user_can() {
128
		return current_user_can( get_post_type_object( $this->screen->post_type )->cap->edit_posts );
129
	}
130
131
	/**
132
	 *
133
	 * @global array    $avail_post_stati
134
	 * @global WP_Query $wp_query
135
	 * @global int      $per_page
136
	 * @global string   $mode
137
	 */
138
	public function prepare_items() {
139
		global $avail_post_stati, $wp_query, $per_page, $mode;
140
141
		// is going to call wp()
142
		$avail_post_stati = wp_edit_posts_query();
143
144
		$this->set_hierarchical_display( is_post_type_hierarchical( $this->screen->post_type ) && 'menu_order title' === $wp_query->query['orderby'] );
145
146
		$post_type = $this->screen->post_type;
147
		$per_page = $this->get_items_per_page( 'edit_' . $post_type . '_per_page' );
148
149
		/** This filter is documented in wp-admin/includes/post.php */
150
 		$per_page = apply_filters( 'edit_posts_per_page', $per_page, $post_type );
151
152
		if ( $this->hierarchical_display ) {
153
			$total_items = $wp_query->post_count;
154
		} elseif ( $wp_query->found_posts || $this->get_pagenum() === 1 ) {
155
			$total_items = $wp_query->found_posts;
156
		} else {
157
			$post_counts = (array) wp_count_posts( $post_type, 'readable' );
158
159
			if ( isset( $_REQUEST['post_status'] ) && in_array( $_REQUEST['post_status'] , $avail_post_stati ) ) {
160
				$total_items = $post_counts[ $_REQUEST['post_status'] ];
161
			} elseif ( isset( $_REQUEST['show_sticky'] ) && $_REQUEST['show_sticky'] ) {
162
				$total_items = $this->sticky_posts_count;
163
			} elseif ( isset( $_GET['author'] ) && $_GET['author'] == get_current_user_id() ) {
164
				$total_items = $this->user_posts_count;
165
			} else {
166
				$total_items = array_sum( $post_counts );
167
168
				// Subtract post types that are not included in the admin all list.
169
				foreach ( get_post_stati( array( 'show_in_admin_all_list' => false ) ) as $state ) {
170
					$total_items -= $post_counts[ $state ];
171
				}
172
			}
173
		}
174
175 View Code Duplication
		if ( ! empty( $_REQUEST['mode'] ) ) {
176
			$mode = $_REQUEST['mode'] === 'excerpt' ? 'excerpt' : 'list';
177
			set_user_setting( 'posts_list_mode', $mode );
178
		} else {
179
			$mode = get_user_setting( 'posts_list_mode', 'list' );
180
		}
181
182
		$this->is_trash = isset( $_REQUEST['post_status'] ) && $_REQUEST['post_status'] === 'trash';
183
184
		$this->set_pagination_args( array(
185
			'total_items' => $total_items,
186
			'per_page' => $per_page
187
		) );
188
	}
189
190
	/**
191
	 *
192
	 * @return bool
193
	 */
194
	public function has_items() {
195
		return have_posts();
196
	}
197
198
	/**
199
	 * @access public
200
	 */
201
	public function no_items() {
202
		if ( isset( $_REQUEST['post_status'] ) && 'trash' === $_REQUEST['post_status'] )
203
			echo get_post_type_object( $this->screen->post_type )->labels->not_found_in_trash;
204
		else
205
			echo get_post_type_object( $this->screen->post_type )->labels->not_found;
206
	}
207
208
	/**
209
	 * Determine if the current view is the "All" view.
210
	 *
211
	 * @since 4.2.0
212
	 *
213
	 * @return bool Whether the current view is the "All" view.
214
	 */
215
	protected function is_base_request() {
216
		$vars = $_GET;
217
		unset( $vars['paged'] );
218
219
		if ( empty( $vars ) ) {
220
			return true;
221
		} elseif ( 1 === count( $vars ) && ! empty( $vars['post_type'] ) ) {
222
			return $this->screen->post_type === $vars['post_type'];
223
		}
224
225
		return 1 === count( $vars ) && ! empty( $vars['mode'] );
226
	}
227
228
	/**
229
	 * Helper to create links to edit.php with params.
230
	 *
231
	 * @since 4.4.0
232
	 * @access protected
233
	 *
234
	 * @param array  $args  URL parameters for the link.
235
	 * @param string $label Link text.
236
	 * @param string $class Optional. Class attribute. Default empty string.
237
	 * @return string The formatted link string.
238
	 */
239
	protected function get_edit_link( $args, $label, $class = '' ) {
240
		$url = add_query_arg( $args, 'edit.php' );
241
242
		$class_html = '';
243
		if ( ! empty( $class ) ) {
244
			 $class_html = sprintf(
245
				' class="%s"',
246
				esc_attr( $class )
247
			);
248
		}
249
250
		return sprintf(
251
			'<a href="%s"%s>%s</a>',
252
			esc_url( $url ),
253
			$class_html,
254
			$label
255
		);
256
	}
257
258
	/**
259
	 *
260
	 * @global array $locked_post_status This seems to be deprecated.
261
	 * @global array $avail_post_stati
262
	 * @return array
263
	 */
264
	protected function get_views() {
265
		global $locked_post_status, $avail_post_stati;
266
267
		$post_type = $this->screen->post_type;
268
269
		if ( !empty($locked_post_status) )
270
			return array();
271
272
		$status_links = array();
273
		$num_posts = wp_count_posts( $post_type, 'readable' );
274
		$total_posts = array_sum( (array) $num_posts );
275
		$class = '';
276
277
		$current_user_id = get_current_user_id();
278
		$all_args = array( 'post_type' => $post_type );
279
		$mine = '';
280
281
		// Subtract post types that are not included in the admin all list.
282
		foreach ( get_post_stati( array( 'show_in_admin_all_list' => false ) ) as $state ) {
283
			$total_posts -= $num_posts->$state;
284
		}
285
286
		if ( $this->user_posts_count && $this->user_posts_count !== $total_posts ) {
287
			if ( isset( $_GET['author'] ) && ( $_GET['author'] == $current_user_id ) ) {
288
				$class = 'current';
289
			}
290
291
			$mine_args = array(
292
				'post_type' => $post_type,
293
				'author' => $current_user_id
294
			);
295
296
			$mine_inner_html = sprintf(
297
				_nx(
298
					'Mine <span class="count">(%s)</span>',
299
					'Mine <span class="count">(%s)</span>',
300
					$this->user_posts_count,
301
					'posts'
302
				),
303
				number_format_i18n( $this->user_posts_count )
304
			);
305
306
			$mine = $this->get_edit_link( $mine_args, $mine_inner_html, $class );
307
308
			$all_args['all_posts'] = 1;
309
			$class = '';
310
		}
311
312
		if ( empty( $class ) && ( $this->is_base_request() || isset( $_REQUEST['all_posts'] ) ) ) {
313
			$class = 'current';
314
		}
315
316
		$all_inner_html = sprintf(
317
			_nx(
318
				'All <span class="count">(%s)</span>',
319
				'All <span class="count">(%s)</span>',
320
				$total_posts,
321
				'posts'
322
			),
323
			number_format_i18n( $total_posts )
324
		);
325
326
		$status_links['all'] = $this->get_edit_link( $all_args, $all_inner_html, $class );
327
		if ( $mine ) {
328
			$status_links['mine'] = $mine;
329
		}
330
331
		foreach ( get_post_stati(array('show_in_admin_status_list' => true), 'objects') as $status ) {
332
			$class = '';
333
334
			$status_name = $status->name;
335
336
			if ( ! in_array( $status_name, $avail_post_stati ) || empty( $num_posts->$status_name ) ) {
337
				continue;
338
			}
339
340
			if ( isset($_REQUEST['post_status']) && $status_name === $_REQUEST['post_status'] ) {
341
				$class = 'current';
342
			}
343
344
			$status_args = array(
345
				'post_status' => $status_name,
346
				'post_type' => $post_type,
347
			);
348
349
			$status_label = sprintf(
350
				translate_nooped_plural( $status->label_count, $num_posts->$status_name ),
351
				number_format_i18n( $num_posts->$status_name )
352
			);
353
354
			$status_links[ $status_name ] = $this->get_edit_link( $status_args, $status_label, $class );
355
		}
356
357
		if ( ! empty( $this->sticky_posts_count ) ) {
358
			$class = ! empty( $_REQUEST['show_sticky'] ) ? 'current' : '';
359
360
			$sticky_args = array(
361
				'post_type'	=> $post_type,
362
				'show_sticky' => 1
363
			);
364
365
			$sticky_inner_html = sprintf(
366
				_nx(
367
					'Sticky <span class="count">(%s)</span>',
368
					'Sticky <span class="count">(%s)</span>',
369
					$this->sticky_posts_count,
370
					'posts'
371
				),
372
				number_format_i18n( $this->sticky_posts_count )
373
			);
374
375
			$sticky_link = array(
376
				'sticky' => $this->get_edit_link( $sticky_args, $sticky_inner_html, $class )
377
			);
378
379
			// Sticky comes after Publish, or if not listed, after All.
380
			$split = 1 + array_search( ( isset( $status_links['publish'] ) ? 'publish' : 'all' ), array_keys( $status_links ) );
381
			$status_links = array_merge( array_slice( $status_links, 0, $split ), $sticky_link, array_slice( $status_links, $split ) );
382
		}
383
384
		return $status_links;
385
	}
386
387
	/**
388
	 *
389
	 * @return array
390
	 */
391
	protected function get_bulk_actions() {
392
		$actions = array();
393
		$post_type_obj = get_post_type_object( $this->screen->post_type );
394
395
		if ( current_user_can( $post_type_obj->cap->edit_posts ) ) {
396
			if ( $this->is_trash ) {
397
				$actions['untrash'] = __( 'Restore' );
398
			} else {
399
				$actions['edit'] = __( 'Edit' );
400
			}
401
		}
402
403
		if ( current_user_can( $post_type_obj->cap->delete_posts ) ) {
404
			if ( $this->is_trash || ! EMPTY_TRASH_DAYS ) {
405
				$actions['delete'] = __( 'Delete Permanently' );
406
			} else {
407
				$actions['trash'] = __( 'Move to Trash' );
408
			}
409
		}
410
411
		return $actions;
412
	}
413
414
	/**
415
	 * Displays a categories drop-down for filtering on the Posts list table.
416
	 *
417
	 * @since 4.6.0
418
	 * @access protected
419
	 *
420
	 * @global int $cat Currently selected category.
421
	 *
422
	 * @param string $post_type Post type slug.
423
	 */
424
	protected function categories_dropdown( $post_type ) {
425
		global $cat;
426
427
		/**
428
		 * Filters whether to remove the 'Categories' drop-down from the post list table.
429
		 *
430
		 * @since 4.6.0
431
		 *
432
		 * @param bool   $disable   Whether to disable the categories drop-down. Default false.
433
		 * @param string $post_type Post type slug.
434
		 */
435
		if ( false !== apply_filters( 'disable_categories_dropdown', false, $post_type ) ) {
436
			return;
437
		}
438
439
		if ( is_object_in_taxonomy( $post_type, 'category' ) ) {
440
			$dropdown_options = array(
441
				'show_option_all' => get_taxonomy( 'category' )->labels->all_items,
442
				'hide_empty' => 0,
443
				'hierarchical' => 1,
444
				'show_count' => 0,
445
				'orderby' => 'name',
446
				'selected' => $cat
447
			);
448
449
			echo '<label class="screen-reader-text" for="cat">' . __( 'Filter by category' ) . '</label>';
450
			wp_dropdown_categories( $dropdown_options );
451
		}
452
	}
453
454
	/**
455
	 * @param string $which
456
	 */
457
	protected function extra_tablenav( $which ) {
458
?>
459
		<div class="alignleft actions">
460
<?php
461
		if ( 'top' === $which && !is_singular() ) {
462
			ob_start();
463
464
			$this->months_dropdown( $this->screen->post_type );
465
			$this->categories_dropdown( $this->screen->post_type );
466
467
			/**
468
			 * Fires before the Filter button on the Posts and Pages list tables.
469
			 *
470
			 * The Filter button allows sorting by date and/or category on the
471
			 * Posts list table, and sorting by date on the Pages list table.
472
			 *
473
			 * @since 2.1.0
474
			 * @since 4.4.0 The `$post_type` parameter was added.
475
			 * @since 4.6.0 The `$which` parameter was added.
476
			 *
477
			 * @param string $post_type The post type slug.
478
			 * @param string $which     The location of the extra table nav markup:
479
			 *                          'top' or 'bottom' for WP_Posts_List_Table,
480
			 *                          'bar' for WP_Media_List_Table.
481
			 */
482
			do_action( 'restrict_manage_posts', $this->screen->post_type, $which );
483
484
			$output = ob_get_clean();
485
486
			if ( ! empty( $output ) ) {
487
				echo $output;
488
				submit_button( __( 'Filter' ), '', 'filter_action', false, array( 'id' => 'post-query-submit' ) );
489
			}
490
		}
491
492
		if ( $this->is_trash && current_user_can( get_post_type_object( $this->screen->post_type )->cap->edit_others_posts ) && $this->has_items() ) {
493
			submit_button( __( 'Empty Trash' ), 'apply', 'delete_all', false );
494
		}
495
?>
496
		</div>
497
<?php
498
		/**
499
		 * Fires immediately following the closing "actions" div in the tablenav for the posts
500
		 * list table.
501
		 *
502
		 * @since 4.4.0
503
		 *
504
		 * @param string $which The location of the extra table nav markup: 'top' or 'bottom'.
505
		 */
506
		do_action( 'manage_posts_extra_tablenav', $which );
507
	}
508
509
	/**
510
	 *
511
	 * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|false?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
512
	 */
513
	public function current_action() {
514
		if ( isset( $_REQUEST['delete_all'] ) || isset( $_REQUEST['delete_all2'] ) )
515
			return 'delete_all';
516
517
		return parent::current_action();
518
	}
519
520
	/**
521
	 *
522
	 * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use string[].

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
523
	 */
524
	protected function get_table_classes() {
525
		return array( 'widefat', 'fixed', 'striped', is_post_type_hierarchical( $this->screen->post_type ) ? 'pages' : 'posts' );
526
	}
527
528
	/**
529
	 *
530
	 * @return array
531
	 */
532
	public function get_columns() {
533
		$post_type = $this->screen->post_type;
534
535
		$posts_columns = array();
536
537
		$posts_columns['cb'] = '<input type="checkbox" />';
538
539
		/* translators: manage posts column name */
540
		$posts_columns['title'] = _x( 'Title', 'column name' );
541
542
		if ( post_type_supports( $post_type, 'author' ) ) {
543
			$posts_columns['author'] = __( 'Author' );
544
		}
545
546
		$taxonomies = get_object_taxonomies( $post_type, 'objects' );
547
		$taxonomies = wp_filter_object_list( $taxonomies, array( 'show_admin_column' => true ), 'and', 'name' );
548
549
		/**
550
		 * Filters the taxonomy columns in the Posts list table.
551
		 *
552
		 * The dynamic portion of the hook name, `$post_type`, refers to the post
553
		 * type slug.
554
		 *
555
		 * @since 3.5.0
556
		 *
557
		 * @param array  $taxonomies Array of taxonomies to show columns for.
558
		 * @param string $post_type  The post type.
559
		 */
560
		$taxonomies = apply_filters( "manage_taxonomies_for_{$post_type}_columns", $taxonomies, $post_type );
561
		$taxonomies = array_filter( $taxonomies, 'taxonomy_exists' );
562
563 View Code Duplication
		foreach ( $taxonomies as $taxonomy ) {
564
			if ( 'category' === $taxonomy )
565
				$column_key = 'categories';
566
			elseif ( 'post_tag' === $taxonomy )
567
				$column_key = 'tags';
568
			else
569
				$column_key = 'taxonomy-' . $taxonomy;
570
571
			$posts_columns[ $column_key ] = get_taxonomy( $taxonomy )->labels->name;
572
		}
573
574
		$post_status = !empty( $_REQUEST['post_status'] ) ? $_REQUEST['post_status'] : 'all';
575
		if ( post_type_supports( $post_type, 'comments' ) && !in_array( $post_status, array( 'pending', 'draft', 'future' ) ) )
576
			$posts_columns['comments'] = '<span class="vers comment-grey-bubble" title="' . esc_attr__( 'Comments' ) . '"><span class="screen-reader-text">' . __( 'Comments' ) . '</span></span>';
577
578
		$posts_columns['date'] = __( 'Date' );
579
580
		if ( 'page' === $post_type ) {
581
582
			/**
583
			 * Filters the columns displayed in the Pages list table.
584
			 *
585
			 * @since 2.5.0
586
			 *
587
			 * @param array $post_columns An array of column names.
588
			 */
589
			$posts_columns = apply_filters( 'manage_pages_columns', $posts_columns );
590
		} else {
591
592
			/**
593
			 * Filters the columns displayed in the Posts list table.
594
			 *
595
			 * @since 1.5.0
596
			 *
597
			 * @param array  $posts_columns An array of column names.
598
			 * @param string $post_type     The post type slug.
599
			 */
600
			$posts_columns = apply_filters( 'manage_posts_columns', $posts_columns, $post_type );
601
		}
602
603
		/**
604
		 * Filters the columns displayed in the Posts list table for a specific post type.
605
		 *
606
		 * The dynamic portion of the hook name, `$post_type`, refers to the post type slug.
607
		 *
608
		 * @since 3.0.0
609
		 *
610
		 * @param array $post_columns An array of column names.
611
		 */
612
		return apply_filters( "manage_{$post_type}_posts_columns", $posts_columns );
613
	}
614
615
	/**
616
	 *
617
	 * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,string|array<string|boolean>>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
618
	 */
619 View Code Duplication
	protected function get_sortable_columns() {
620
		return array(
621
			'title'    => 'title',
622
			'parent'   => 'parent',
623
			'comments' => 'comment_count',
624
			'date'     => array( 'date', true )
625
		);
626
	}
627
628
	/**
629
	 * @global WP_Query $wp_query
630
	 * @global int $per_page
631
	 * @param array $posts
632
	 * @param int $level
633
	 */
634
	public function display_rows( $posts = array(), $level = 0 ) {
635
		global $wp_query, $per_page;
636
637
		if ( empty( $posts ) )
638
			$posts = $wp_query->posts;
639
640
		add_filter( 'the_title', 'esc_html' );
641
642
		if ( $this->hierarchical_display ) {
643
			$this->_display_rows_hierarchical( $posts, $this->get_pagenum(), $per_page );
644
		} else {
645
			$this->_display_rows( $posts, $level );
646
		}
647
	}
648
649
	/**
650
	 * @param array $posts
651
	 * @param int $level
652
	 */
653
	private function _display_rows( $posts, $level = 0 ) {
654
		// Create array of post IDs.
655
		$post_ids = array();
656
657
		foreach ( $posts as $a_post )
658
			$post_ids[] = $a_post->ID;
659
660
		$this->comment_pending_count = get_pending_comments_num( $post_ids );
0 ignored issues
show
Documentation Bug introduced by
It seems like get_pending_comments_num($post_ids) can also be of type integer or double. However, the property $comment_pending_count is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
661
662
		foreach ( $posts as $post )
663
			$this->single_row( $post, $level );
664
	}
665
666
	/**
667
	 * @global wpdb    $wpdb
668
	 * @global WP_Post $post
669
	 * @param array $pages
670
	 * @param int $pagenum
671
	 * @param int $per_page
672
	 */
673
	private function _display_rows_hierarchical( $pages, $pagenum = 1, $per_page = 20 ) {
674
		global $wpdb;
675
676
		$level = 0;
677
678
		if ( ! $pages ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $pages of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
679
			$pages = get_pages( array( 'sort_column' => 'menu_order' ) );
680
681
			if ( ! $pages )
682
				return;
683
		}
684
685
		/*
686
		 * Arrange pages into two parts: top level pages and children_pages
687
		 * children_pages is two dimensional array, eg.
688
		 * children_pages[10][] contains all sub-pages whose parent is 10.
689
		 * It only takes O( N ) to arrange this and it takes O( 1 ) for subsequent lookup operations
690
		 * If searching, ignore hierarchy and treat everything as top level
691
		 */
692
		if ( empty( $_REQUEST['s'] ) ) {
693
694
			$top_level_pages = array();
695
			$children_pages = array();
696
697
			foreach ( $pages as $page ) {
698
699
				// Catch and repair bad pages.
700
				if ( $page->post_parent == $page->ID ) {
701
					$page->post_parent = 0;
702
					$wpdb->update( $wpdb->posts, array( 'post_parent' => 0 ), array( 'ID' => $page->ID ) );
703
					clean_post_cache( $page );
704
				}
705
706
				if ( 0 == $page->post_parent )
707
					$top_level_pages[] = $page;
708
				else
709
					$children_pages[ $page->post_parent ][] = $page;
710
			}
711
712
			$pages = &$top_level_pages;
713
		}
714
715
		$count = 0;
716
		$start = ( $pagenum - 1 ) * $per_page;
717
		$end = $start + $per_page;
718
		$to_display = array();
719
720
		foreach ( $pages as $page ) {
721
			if ( $count >= $end )
722
				break;
723
724
			if ( $count >= $start ) {
725
				$to_display[$page->ID] = $level;
726
			}
727
728
			$count++;
729
730
			if ( isset( $children_pages ) )
731
				$this->_page_rows( $children_pages, $count, $page->ID, $level + 1, $pagenum, $per_page, $to_display );
732
		}
733
734
		// If it is the last pagenum and there are orphaned pages, display them with paging as well.
735
		if ( isset( $children_pages ) && $count < $end ){
736
			foreach ( $children_pages as $orphans ){
737
				foreach ( $orphans as $op ) {
738
					if ( $count >= $end )
739
						break;
740
741
					if ( $count >= $start ) {
742
						$to_display[$op->ID] = 0;
743
					}
744
745
					$count++;
746
				}
747
			}
748
		}
749
750
		$ids = array_keys( $to_display );
751
		_prime_post_caches( $ids );
752
753
		if ( ! isset( $GLOBALS['post'] ) ) {
754
			$GLOBALS['post'] = reset( $ids );
755
		}
756
757
		foreach ( $to_display as $page_id => $level ) {
758
			echo "\t";
759
			$this->single_row( $page_id, $level );
760
		}
761
	}
762
763
	/**
764
	 * Given a top level page ID, display the nested hierarchy of sub-pages
765
	 * together with paging support
766
	 *
767
	 * @since 3.1.0 (Standalone function exists since 2.6.0)
768
	 * @since 4.2.0 Added the `$to_display` parameter.
769
	 *
770
	 * @param array $children_pages
771
	 * @param int $count
772
	 * @param int $parent
773
	 * @param int $level
774
	 * @param int $pagenum
775
	 * @param int $per_page
776
	 * @param array $to_display List of pages to be displayed. Passed by reference.
777
	 */
778
	private function _page_rows( &$children_pages, &$count, $parent, $level, $pagenum, $per_page, &$to_display ) {
779
		if ( ! isset( $children_pages[$parent] ) )
780
			return;
781
782
		$start = ( $pagenum - 1 ) * $per_page;
783
		$end = $start + $per_page;
784
785
		foreach ( $children_pages[$parent] as $page ) {
786
			if ( $count >= $end )
787
				break;
788
789
			// If the page starts in a subtree, print the parents.
790
			if ( $count == $start && $page->post_parent > 0 ) {
791
				$my_parents = array();
792
				$my_parent = $page->post_parent;
793
				while ( $my_parent ) {
794
					// Get the ID from the list or the attribute if my_parent is an object
795
					$parent_id = $my_parent;
796
					if ( is_object( $my_parent ) ) {
797
						$parent_id = $my_parent->ID;
798
					}
799
800
					$my_parent = get_post( $parent_id );
801
					$my_parents[] = $my_parent;
802
					if ( !$my_parent->post_parent )
803
						break;
804
					$my_parent = $my_parent->post_parent;
805
				}
806
				$num_parents = count( $my_parents );
807 View Code Duplication
				while ( $my_parent = array_pop( $my_parents ) ) {
808
					$to_display[$my_parent->ID] = $level - $num_parents;
809
					$num_parents--;
810
				}
811
			}
812
813
			if ( $count >= $start ) {
814
				$to_display[$page->ID] = $level;
815
			}
816
817
			$count++;
818
819
			$this->_page_rows( $children_pages, $count, $page->ID, $level + 1, $pagenum, $per_page, $to_display );
820
		}
821
822
		unset( $children_pages[$parent] ); //required in order to keep track of orphans
823
	}
824
825
	/**
826
	 * Handles the checkbox column output.
827
	 *
828
	 * @since 4.3.0
829
	 * @access public
830
	 *
831
	 * @param WP_Post $post The current WP_Post object.
832
	 */
833
	public function column_cb( $post ) {
834
		if ( current_user_can( 'edit_post', $post->ID ) ): ?>
835
			<label class="screen-reader-text" for="cb-select-<?php the_ID(); ?>"><?php
836
				printf( __( 'Select %s' ), _draft_or_post_title() );
837
			?></label>
838
			<input id="cb-select-<?php the_ID(); ?>" type="checkbox" name="post[]" value="<?php the_ID(); ?>" />
839
			<div class="locked-indicator">
840
				<span class="locked-indicator-icon" aria-hidden="true"></span>
841
				<span class="screen-reader-text"><?php
842
				printf(
843
					/* translators: %s: post title */
844
					__( '&#8220;%s&#8221; is locked' ),
845
					_draft_or_post_title()
846
				);
847
				?></span>
848
			</div>
849
		<?php endif;
850
	}
851
852
	/**
853
	 * @since 4.3.0
854
	 * @access protected
855
	 *
856
	 * @param WP_Post $post
857
	 * @param string  $classes
858
	 * @param string  $data
859
	 * @param string  $primary
860
	 */
861
	protected function _column_title( $post, $classes, $data, $primary ) {
862
		echo '<td class="' . $classes . ' page-title" ', $data, '>';
863
		echo $this->column_title( $post );
864
		echo $this->handle_row_actions( $post, 'title', $primary );
865
		echo '</td>';
866
	}
867
868
	/**
869
	 * Handles the title column output.
870
	 *
871
	 * @since 4.3.0
872
	 * @access public
873
	 *
874
	 * @global string $mode List table view mode.
875
	 *
876
	 * @param WP_Post $post The current WP_Post object.
877
	 */
878
	public function column_title( $post ) {
879
		global $mode;
880
881
		if ( $this->hierarchical_display ) {
882
			if ( 0 === $this->current_level && (int) $post->post_parent > 0 ) {
883
				// Sent level 0 by accident, by default, or because we don't know the actual level.
884
				$find_main_page = (int) $post->post_parent;
885
				while ( $find_main_page > 0 ) {
886
					$parent = get_post( $find_main_page );
887
888
					if ( is_null( $parent ) ) {
889
						break;
890
					}
891
892
					$this->current_level++;
893
					$find_main_page = (int) $parent->post_parent;
894
895
					if ( ! isset( $parent_name ) ) {
896
						/** This filter is documented in wp-includes/post-template.php */
897
						$parent_name = apply_filters( 'the_title', $parent->post_title, $parent->ID );
898
					}
899
				}
900
			}
901
		}
902
903
		$can_edit_post = current_user_can( 'edit_post', $post->ID );
904
905
		if ( $can_edit_post && $post->post_status != 'trash' ) {
906
			$lock_holder = wp_check_post_lock( $post->ID );
907
908
			if ( $lock_holder ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $lock_holder of type integer|false is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
909
				$lock_holder = get_userdata( $lock_holder );
910
				$locked_avatar = get_avatar( $lock_holder->ID, 18 );
911
				$locked_text = esc_html( sprintf( __( '%s is currently editing' ), $lock_holder->display_name ) );
912
			} else {
913
				$locked_avatar = $locked_text = '';
914
			}
915
916
			echo '<div class="locked-info"><span class="locked-avatar">' . $locked_avatar . '</span> <span class="locked-text">' . $locked_text . "</span></div>\n";
917
		}
918
919
		$pad = str_repeat( '&#8212; ', $this->current_level );
920
		echo "<strong>";
921
922
		$format = get_post_format( $post->ID );
923
		if ( $format ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $format of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
924
			$label = get_post_format_string( $format );
925
926
			$format_class = 'post-state-format post-format-icon post-format-' . $format;
927
928
			$format_args = array(
929
				'post_format' => $format,
930
				'post_type' => $post->post_type
931
			);
932
933
			echo $this->get_edit_link( $format_args, $label . ':', $format_class );
934
		}
935
936
		$title = _draft_or_post_title();
937
938
		if ( $can_edit_post && $post->post_status != 'trash' ) {
939
			printf(
940
				'<a class="row-title" href="%s" aria-label="%s">%s%s</a>',
941
				get_edit_post_link( $post->ID ),
942
				/* translators: %s: post title */
943
				esc_attr( sprintf( __( '&#8220;%s&#8221; (Edit)' ), $title ) ),
944
				$pad,
945
				$title
946
			);
947
		} else {
948
			echo $pad . $title;
949
		}
950
		_post_states( $post );
951
952
		if ( isset( $parent_name ) ) {
953
			$post_type_object = get_post_type_object( $post->post_type );
954
			echo ' | ' . $post_type_object->labels->parent_item_colon . ' ' . esc_html( $parent_name );
955
		}
956
		echo "</strong>\n";
957
958
		if ( ! is_post_type_hierarchical( $this->screen->post_type ) && 'excerpt' === $mode && current_user_can( 'read_post', $post->ID ) ) {
959
			echo esc_html( get_the_excerpt() );
960
		}
961
962
		get_inline_data( $post );
963
	}
964
965
	/**
966
	 * Handles the post date column output.
967
	 *
968
	 * @since 4.3.0
969
	 * @access public
970
	 *
971
	 * @global string $mode List table view mode.
972
	 *
973
	 * @param WP_Post $post The current WP_Post object.
974
	 */
975
	public function column_date( $post ) {
976
		global $mode;
977
978
		if ( '0000-00-00 00:00:00' === $post->post_date ) {
979
			$t_time = $h_time = __( 'Unpublished' );
980
			$time_diff = 0;
981
		} else {
982
			$t_time = get_the_time( __( 'Y/m/d g:i:s a' ) );
983
			$m_time = $post->post_date;
984
			$time = get_post_time( 'G', true, $post );
985
986
			$time_diff = time() - $time;
987
988
			if ( $time_diff > 0 && $time_diff < DAY_IN_SECONDS ) {
989
				$h_time = sprintf( __( '%s ago' ), human_time_diff( $time ) );
990
			} else {
991
				$h_time = mysql2date( __( 'Y/m/d' ), $m_time );
992
			}
993
		}
994
995
		if ( 'publish' === $post->post_status ) {
996
			$status = __( 'Published' );
997
		} elseif ( 'future' === $post->post_status ) {
998
			if ( $time_diff > 0 ) {
999
				$status = '<strong class="error-message">' . __( 'Missed schedule' ) . '</strong>';
1000
			} else {
1001
				$status = __( 'Scheduled' );
1002
			}
1003
		} else {
1004
			$status = __( 'Last Modified' );
1005
		}
1006
1007
		/**
1008
		 * Filters the status text of the post.
1009
		 *
1010
		 * @since 4.8.0
1011
		 *
1012
		 * @param string  $status      The status text.
1013
		 * @param WP_Post $post        Post object.
1014
		 * @param string  $column_name The column name.
1015
		 * @param string  $mode        The list display mode ('excerpt' or 'list').
1016
		 */
1017
		$status = apply_filters( 'post_date_column_status', $status, $post, 'date', $mode );
1018
1019
		if ( $status ) {
1020
			echo $status . '<br />';
1021
		}
1022
1023
		if ( 'excerpt' === $mode ) {
1024
			/**
1025
			 * Filters the published time of the post.
1026
			 *
1027
			 * If `$mode` equals 'excerpt', the published time and date are both displayed.
1028
			 * If `$mode` equals 'list' (default), the publish date is displayed, with the
1029
			 * time and date together available as an abbreviation definition.
1030
			 *
1031
			 * @since 2.5.1
1032
			 *
1033
			 * @param string  $t_time      The published time.
1034
			 * @param WP_Post $post        Post object.
1035
			 * @param string  $column_name The column name.
1036
			 * @param string  $mode        The list display mode ('excerpt' or 'list').
1037
			 */
1038
			echo apply_filters( 'post_date_column_time', $t_time, $post, 'date', $mode );
1039
		} else {
1040
1041
			/** This filter is documented in wp-admin/includes/class-wp-posts-list-table.php */
1042
			echo '<abbr title="' . $t_time . '">' . apply_filters( 'post_date_column_time', $h_time, $post, 'date', $mode ) . '</abbr>';
1043
		}
1044
	}
1045
1046
	/**
1047
	 * Handles the comments column output.
1048
	 *
1049
	 * @since 4.3.0
1050
	 * @access public
1051
	 *
1052
	 * @param WP_Post $post The current WP_Post object.
1053
	 */
1054
	public function column_comments( $post ) {
1055
		?>
1056
		<div class="post-com-count-wrapper">
1057
		<?php
1058
			$pending_comments = isset( $this->comment_pending_count[$post->ID] ) ? $this->comment_pending_count[$post->ID] : 0;
1059
1060
			$this->comments_bubble( $post->ID, $pending_comments );
1061
		?>
1062
		</div>
1063
		<?php
1064
	}
1065
1066
	/**
1067
	 * Handles the post author column output.
1068
	 *
1069
	 * @since 4.3.0
1070
	 * @access public
1071
	 *
1072
	 * @param WP_Post $post The current WP_Post object.
1073
	 */
1074
	public function column_author( $post ) {
1075
		$args = array(
1076
			'post_type' => $post->post_type,
1077
			'author' => get_the_author_meta( 'ID' )
1078
		);
1079
		echo $this->get_edit_link( $args, get_the_author() );
1080
	}
1081
1082
	/**
1083
	 * Handles the default column output.
1084
	 *
1085
	 * @since 4.3.0
1086
	 * @access public
1087
	 *
1088
	 * @param WP_Post $post        The current WP_Post object.
1089
	 * @param string  $column_name The current column name.
1090
	 */
1091
	public function column_default( $post, $column_name ) {
1092 View Code Duplication
		if ( 'categories' === $column_name ) {
1093
			$taxonomy = 'category';
1094
		} elseif ( 'tags' === $column_name ) {
1095
			$taxonomy = 'post_tag';
1096
		} elseif ( 0 === strpos( $column_name, 'taxonomy-' ) ) {
1097
			$taxonomy = substr( $column_name, 9 );
1098
		} else {
1099
			$taxonomy = false;
1100
		}
1101
		if ( $taxonomy ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $taxonomy of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1102
			$taxonomy_object = get_taxonomy( $taxonomy );
1103
			$terms = get_the_terms( $post->ID, $taxonomy );
1104
			if ( is_array( $terms ) ) {
1105
				$out = array();
1106
				foreach ( $terms as $t ) {
1107
					$posts_in_term_qv = array();
1108
					if ( 'post' != $post->post_type ) {
1109
						$posts_in_term_qv['post_type'] = $post->post_type;
1110
					}
1111
					if ( $taxonomy_object->query_var ) {
1112
						$posts_in_term_qv[ $taxonomy_object->query_var ] = $t->slug;
1113
					} else {
1114
						$posts_in_term_qv['taxonomy'] = $taxonomy;
1115
						$posts_in_term_qv['term'] = $t->slug;
1116
					}
1117
1118
					$label = esc_html( sanitize_term_field( 'name', $t->name, $t->term_id, $taxonomy, 'display' ) );
1119
					$out[] = $this->get_edit_link( $posts_in_term_qv, $label );
1120
				}
1121
				/* translators: used between list items, there is a space after the comma */
1122
				echo join( __( ', ' ), $out );
1123
			} else {
1124
				echo '<span aria-hidden="true">&#8212;</span><span class="screen-reader-text">' . $taxonomy_object->labels->no_terms . '</span>';
1125
			}
1126
			return;
1127
		}
1128
1129
		if ( is_post_type_hierarchical( $post->post_type ) ) {
1130
1131
			/**
1132
			 * Fires in each custom column on the Posts list table.
1133
			 *
1134
			 * This hook only fires if the current post type is hierarchical,
1135
			 * such as pages.
1136
			 *
1137
			 * @since 2.5.0
1138
			 *
1139
			 * @param string $column_name The name of the column to display.
1140
			 * @param int    $post_id     The current post ID.
1141
			 */
1142
			do_action( 'manage_pages_custom_column', $column_name, $post->ID );
1143
		} else {
1144
1145
			/**
1146
			 * Fires in each custom column in the Posts list table.
1147
			 *
1148
			 * This hook only fires if the current post type is non-hierarchical,
1149
			 * such as posts.
1150
			 *
1151
			 * @since 1.5.0
1152
			 *
1153
			 * @param string $column_name The name of the column to display.
1154
			 * @param int    $post_id     The current post ID.
1155
			 */
1156
			do_action( 'manage_posts_custom_column', $column_name, $post->ID );
1157
		}
1158
1159
		/**
1160
		 * Fires for each custom column of a specific post type in the Posts list table.
1161
		 *
1162
		 * The dynamic portion of the hook name, `$post->post_type`, refers to the post type.
1163
		 *
1164
		 * @since 3.1.0
1165
		 *
1166
		 * @param string $column_name The name of the column to display.
1167
		 * @param int    $post_id     The current post ID.
1168
		 */
1169
		do_action( "manage_{$post->post_type}_posts_custom_column", $column_name, $post->ID );
1170
	}
1171
1172
	/**
1173
	 * @global WP_Post $post
1174
	 *
1175
	 * @param int|WP_Post $post
1176
	 * @param int         $level
1177
	 */
1178
	public function single_row( $post, $level = 0 ) {
1179
		$global_post = get_post();
1180
1181
		$post = get_post( $post );
1182
		$this->current_level = $level;
1183
1184
		$GLOBALS['post'] = $post;
1185
		setup_postdata( $post );
1186
1187
		$classes = 'iedit author-' . ( get_current_user_id() == $post->post_author ? 'self' : 'other' );
1188
1189
		$lock_holder = wp_check_post_lock( $post->ID );
1190
		if ( $lock_holder ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $lock_holder of type integer|false is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
1191
			$classes .= ' wp-locked';
1192
		}
1193
1194
		if ( $post->post_parent ) {
1195
		    $count = count( get_post_ancestors( $post->ID ) );
1196
		    $classes .= ' level-'. $count;
1197
		} else {
1198
		    $classes .= ' level-0';
1199
		}
1200
	?>
1201
		<tr id="post-<?php echo $post->ID; ?>" class="<?php echo implode( ' ', get_post_class( $classes, $post->ID ) ); ?>">
1202
			<?php $this->single_row_columns( $post ); ?>
1203
		</tr>
1204
	<?php
1205
		$GLOBALS['post'] = $global_post;
1206
	}
1207
1208
	/**
1209
	 * Gets the name of the default primary column.
1210
	 *
1211
	 * @since 4.3.0
1212
	 * @access protected
1213
	 *
1214
	 * @return string Name of the default primary column, in this case, 'title'.
1215
	 */
1216
	protected function get_default_primary_column_name() {
1217
		return 'title';
1218
	}
1219
1220
	/**
1221
	 * Generates and displays row action links.
1222
	 *
1223
	 * @since 4.3.0
1224
	 * @access protected
1225
	 *
1226
	 * @param object $post        Post being acted upon.
1227
	 * @param string $column_name Current column name.
1228
	 * @param string $primary     Primary column name.
1229
	 * @return string Row actions output for posts.
1230
	 */
1231
	protected function handle_row_actions( $post, $column_name, $primary ) {
1232
		if ( $primary !== $column_name ) {
1233
			return '';
1234
		}
1235
1236
		$post_type_object = get_post_type_object( $post->post_type );
1237
		$can_edit_post = current_user_can( 'edit_post', $post->ID );
1238
		$actions = array();
1239
		$title = _draft_or_post_title();
1240
1241 View Code Duplication
		if ( $can_edit_post && 'trash' != $post->post_status ) {
1242
			$actions['edit'] = sprintf(
1243
				'<a href="%s" aria-label="%s">%s</a>',
1244
				get_edit_post_link( $post->ID ),
1245
				/* translators: %s: post title */
1246
				esc_attr( sprintf( __( 'Edit &#8220;%s&#8221;' ), $title ) ),
1247
				__( 'Edit' )
1248
			);
1249
			$actions['inline hide-if-no-js'] = sprintf(
1250
				'<a href="#" class="editinline" aria-label="%s">%s</a>',
1251
				/* translators: %s: post title */
1252
				esc_attr( sprintf( __( 'Quick edit &#8220;%s&#8221; inline' ), $title ) ),
1253
				__( 'Quick&nbsp;Edit' )
1254
			);
1255
		}
1256
1257
		if ( current_user_can( 'delete_post', $post->ID ) ) {
1258
			if ( 'trash' === $post->post_status ) {
1259
				$actions['untrash'] = sprintf(
1260
					'<a href="%s" aria-label="%s">%s</a>',
1261
					wp_nonce_url( admin_url( sprintf( $post_type_object->_edit_link . '&amp;action=untrash', $post->ID ) ), 'untrash-post_' . $post->ID ),
1262
					/* translators: %s: post title */
1263
					esc_attr( sprintf( __( 'Restore &#8220;%s&#8221; from the Trash' ), $title ) ),
1264
					__( 'Restore' )
1265
				);
1266
			} elseif ( EMPTY_TRASH_DAYS ) {
1267
				$actions['trash'] = sprintf(
1268
					'<a href="%s" class="submitdelete" aria-label="%s">%s</a>',
1269
					get_delete_post_link( $post->ID ),
1270
					/* translators: %s: post title */
1271
					esc_attr( sprintf( __( 'Move &#8220;%s&#8221; to the Trash' ), $title ) ),
1272
					_x( 'Trash', 'verb' )
1273
				);
1274
			}
1275 View Code Duplication
			if ( 'trash' === $post->post_status || ! EMPTY_TRASH_DAYS ) {
1276
				$actions['delete'] = sprintf(
1277
					'<a href="%s" class="submitdelete" aria-label="%s">%s</a>',
1278
					get_delete_post_link( $post->ID, '', true ),
1279
					/* translators: %s: post title */
1280
					esc_attr( sprintf( __( 'Delete &#8220;%s&#8221; permanently' ), $title ) ),
1281
					__( 'Delete Permanently' )
1282
				);
1283
			}
1284
		}
1285
1286
		if ( is_post_type_viewable( $post_type_object ) ) {
0 ignored issues
show
Bug introduced by
It seems like $post_type_object defined by get_post_type_object($post->post_type) on line 1236 can be null; however, is_post_type_viewable() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
1287
			if ( in_array( $post->post_status, array( 'pending', 'draft', 'future' ) ) ) {
1288
				if ( $can_edit_post ) {
1289
					$preview_link = get_preview_post_link( $post );
1290
					$actions['view'] = sprintf(
1291
						'<a href="%s" rel="bookmark" aria-label="%s">%s</a>',
1292
						esc_url( $preview_link ),
1293
						/* translators: %s: post title */
1294
						esc_attr( sprintf( __( 'Preview &#8220;%s&#8221;' ), $title ) ),
1295
						__( 'Preview' )
1296
					);
1297
				}
1298
			} elseif ( 'trash' != $post->post_status ) {
1299
				$actions['view'] = sprintf(
1300
					'<a href="%s" rel="bookmark" aria-label="%s">%s</a>',
1301
					get_permalink( $post->ID ),
1302
					/* translators: %s: post title */
1303
					esc_attr( sprintf( __( 'View &#8220;%s&#8221;' ), $title ) ),
1304
					__( 'View' )
1305
				);
1306
			}
1307
		}
1308
1309
		if ( is_post_type_hierarchical( $post->post_type ) ) {
1310
1311
			/**
1312
			 * Filters the array of row action links on the Pages list table.
1313
			 *
1314
			 * The filter is evaluated only for hierarchical post types.
1315
			 *
1316
			 * @since 2.8.0
1317
			 *
1318
			 * @param array $actions An array of row action links. Defaults are
1319
			 *                         'Edit', 'Quick Edit', 'Restore', 'Trash',
1320
			 *                         'Delete Permanently', 'Preview', and 'View'.
1321
			 * @param WP_Post $post The post object.
1322
			 */
1323
			$actions = apply_filters( 'page_row_actions', $actions, $post );
1324
		} else {
1325
1326
			/**
1327
			 * Filters the array of row action links on the Posts list table.
1328
			 *
1329
			 * The filter is evaluated only for non-hierarchical post types.
1330
			 *
1331
			 * @since 2.8.0
1332
			 *
1333
			 * @param array $actions An array of row action links. Defaults are
1334
			 *                         'Edit', 'Quick Edit', 'Restore', 'Trash',
1335
			 *                         'Delete Permanently', 'Preview', and 'View'.
1336
			 * @param WP_Post $post The post object.
1337
			 */
1338
			$actions = apply_filters( 'post_row_actions', $actions, $post );
1339
		}
1340
1341
		return $this->row_actions( $actions );
1342
	}
1343
1344
	/**
1345
	 * Outputs the hidden row displayed when inline editing
1346
	 *
1347
	 * @since 3.1.0
1348
	 *
1349
	 * @global string $mode List table view mode.
1350
	 */
1351
	public function inline_edit() {
1352
		global $mode;
1353
1354
		$screen = $this->screen;
1355
1356
		$post = get_default_post_to_edit( $screen->post_type );
1357
		$post_type_object = get_post_type_object( $screen->post_type );
1358
1359
		$taxonomy_names = get_object_taxonomies( $screen->post_type );
1360
		$hierarchical_taxonomies = array();
1361
		$flat_taxonomies = array();
1362
		foreach ( $taxonomy_names as $taxonomy_name ) {
1363
1364
			$taxonomy = get_taxonomy( $taxonomy_name );
1365
1366
			$show_in_quick_edit = $taxonomy->show_in_quick_edit;
1367
1368
			/**
1369
			 * Filters whether the current taxonomy should be shown in the Quick Edit panel.
1370
			 *
1371
			 * @since 4.2.0
1372
			 *
1373
			 * @param bool   $show_in_quick_edit Whether to show the current taxonomy in Quick Edit.
1374
			 * @param string $taxonomy_name      Taxonomy name.
1375
			 * @param string $post_type          Post type of current Quick Edit post.
1376
			 */
1377
			if ( ! apply_filters( 'quick_edit_show_taxonomy', $show_in_quick_edit, $taxonomy_name, $screen->post_type ) ) {
1378
				continue;
1379
			}
1380
1381
			if ( $taxonomy->hierarchical )
1382
				$hierarchical_taxonomies[] = $taxonomy;
1383
			else
1384
				$flat_taxonomies[] = $taxonomy;
1385
		}
1386
1387
		$m = ( isset( $mode ) && 'excerpt' === $mode ) ? 'excerpt' : 'list';
1388
		$can_publish = current_user_can( $post_type_object->cap->publish_posts );
1389
		$core_columns = array( 'cb' => true, 'date' => true, 'title' => true, 'categories' => true, 'tags' => true, 'comments' => true, 'author' => true );
1390
1391
	?>
1392
1393
	<form method="get"><table style="display: none"><tbody id="inlineedit">
1394
		<?php
1395
		$hclass = count( $hierarchical_taxonomies ) ? 'post' : 'page';
1396
		$bulk = 0;
1397
		while ( $bulk < 2 ) { ?>
1398
1399
		<tr id="<?php echo $bulk ? 'bulk-edit' : 'inline-edit'; ?>" class="inline-edit-row inline-edit-row-<?php echo "$hclass inline-edit-" . $screen->post_type;
1400
			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}";
1401
		?>" style="display: none"><td colspan="<?php echo $this->get_column_count(); ?>" class="colspanchange">
1402
1403
		<fieldset class="inline-edit-col-left">
1404
			<legend class="inline-edit-legend"><?php echo $bulk ? __( 'Bulk Edit' ) : __( 'Quick Edit' ); ?></legend>
1405
			<div class="inline-edit-col">
1406
	<?php
1407
1408
	if ( post_type_supports( $screen->post_type, 'title' ) ) :
1409
		if ( $bulk ) : ?>
1410
			<div id="bulk-title-div">
1411
				<div id="bulk-titles"></div>
1412
			</div>
1413
1414
	<?php else : // $bulk ?>
1415
1416
			<label>
1417
				<span class="title"><?php _e( 'Title' ); ?></span>
1418
				<span class="input-text-wrap"><input type="text" name="post_title" class="ptitle" value="" /></span>
1419
			</label>
1420
1421
			<label>
1422
				<span class="title"><?php _e( 'Slug' ); ?></span>
1423
				<span class="input-text-wrap"><input type="text" name="post_name" value="" /></span>
1424
			</label>
1425
1426
	<?php endif; // $bulk
1427
	endif; // post_type_supports title ?>
1428
1429
	<?php if ( !$bulk ) : ?>
1430
			<fieldset class="inline-edit-date">
1431
			<legend><span class="title"><?php _e( 'Date' ); ?></span></legend>
1432
				<?php touch_time( 1, 1, 0, 1 ); ?>
1433
			</fieldset>
1434
			<br class="clear" />
1435
	<?php endif; // $bulk
1436
1437
		if ( post_type_supports( $screen->post_type, 'author' ) ) :
1438
			$authors_dropdown = '';
1439
1440
			if ( current_user_can( $post_type_object->cap->edit_others_posts ) ) :
1441
				$users_opt = array(
1442
					'hide_if_only_one_author' => false,
1443
					'who' => 'authors',
1444
					'name' => 'post_author',
1445
					'class'=> 'authors',
1446
					'multi' => 1,
1447
					'echo' => 0,
1448
					'show' => 'display_name_with_login',
1449
				);
1450
				if ( $bulk )
1451
					$users_opt['show_option_none'] = __( '&mdash; No Change &mdash;' );
1452
1453
				if ( $authors = wp_dropdown_users( $users_opt ) ) :
1454
					$authors_dropdown  = '<label class="inline-edit-author">';
1455
					$authors_dropdown .= '<span class="title">' . __( 'Author' ) . '</span>';
1456
					$authors_dropdown .= $authors;
1457
					$authors_dropdown .= '</label>';
1458
				endif;
1459
			endif; // authors
1460
	?>
1461
1462
	<?php if ( !$bulk ) echo $authors_dropdown;
1463
	endif; // post_type_supports author
1464
1465
	if ( !$bulk && $can_publish ) :
1466
	?>
1467
1468
			<div class="inline-edit-group wp-clearfix">
1469
				<label class="alignleft">
1470
					<span class="title"><?php _e( 'Password' ); ?></span>
1471
					<span class="input-text-wrap"><input type="text" name="post_password" class="inline-edit-password-input" value="" /></span>
1472
				</label>
1473
1474
				<em class="alignleft inline-edit-or">
1475
					<?php
1476
					/* translators: Between password field and private checkbox on post quick edit interface */
1477
					_e( '&ndash;OR&ndash;' );
1478
					?>
1479
				</em>
1480
				<label class="alignleft inline-edit-private">
1481
					<input type="checkbox" name="keep_private" value="private" />
1482
					<span class="checkbox-title"><?php _e( 'Private' ); ?></span>
1483
				</label>
1484
			</div>
1485
1486
	<?php endif; ?>
1487
1488
		</div></fieldset>
1489
1490
	<?php if ( count( $hierarchical_taxonomies ) && !$bulk ) : ?>
1491
1492
		<fieldset class="inline-edit-col-center inline-edit-categories"><div class="inline-edit-col">
1493
1494
	<?php foreach ( $hierarchical_taxonomies as $taxonomy ) : ?>
1495
1496
			<span class="title inline-edit-categories-label"><?php echo esc_html( $taxonomy->labels->name ) ?></span>
1497
			<input type="hidden" name="<?php echo ( $taxonomy->name === 'category' ) ? 'post_category[]' : 'tax_input[' . esc_attr( $taxonomy->name ) . '][]'; ?>" value="0" />
1498
			<ul class="cat-checklist <?php echo esc_attr( $taxonomy->name )?>-checklist">
1499
				<?php wp_terms_checklist( null, array( 'taxonomy' => $taxonomy->name ) ) ?>
1500
			</ul>
1501
1502
	<?php endforeach; //$hierarchical_taxonomies as $taxonomy ?>
1503
1504
		</div></fieldset>
1505
1506
	<?php endif; // count( $hierarchical_taxonomies ) && !$bulk ?>
1507
1508
		<fieldset class="inline-edit-col-right"><div class="inline-edit-col">
1509
1510
	<?php
1511
		if ( post_type_supports( $screen->post_type, 'author' ) && $bulk )
1512
			echo $authors_dropdown;
0 ignored issues
show
Bug introduced by
The variable $authors_dropdown does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1513
1514
		if ( post_type_supports( $screen->post_type, 'page-attributes' ) ) :
1515
1516
			if ( $post_type_object->hierarchical ) :
1517
		?>
1518
			<label>
1519
				<span class="title"><?php _e( 'Parent' ); ?></span>
1520
	<?php
1521
		$dropdown_args = array(
1522
			'post_type'         => $post_type_object->name,
1523
			'selected'          => $post->post_parent,
1524
			'name'              => 'post_parent',
1525
			'show_option_none'  => __( 'Main Page (no parent)' ),
1526
			'option_none_value' => 0,
1527
			'sort_column'       => 'menu_order, post_title',
1528
		);
1529
1530
		if ( $bulk )
1531
			$dropdown_args['show_option_no_change'] =  __( '&mdash; No Change &mdash;' );
1532
1533
		/**
1534
		 * Filters the arguments used to generate the Quick Edit page-parent drop-down.
1535
		 *
1536
		 * @since 2.7.0
1537
		 *
1538
		 * @see wp_dropdown_pages()
1539
		 *
1540
		 * @param array $dropdown_args An array of arguments.
1541
		 */
1542
		$dropdown_args = apply_filters( 'quick_edit_dropdown_pages_args', $dropdown_args );
1543
1544
		wp_dropdown_pages( $dropdown_args );
1545
	?>
1546
			</label>
1547
1548
	<?php
1549
			endif; // hierarchical
1550
1551
			if ( !$bulk ) : ?>
1552
1553
			<label>
1554
				<span class="title"><?php _e( 'Order' ); ?></span>
1555
				<span class="input-text-wrap"><input type="text" name="menu_order" class="inline-edit-menu-order-input" value="<?php echo $post->menu_order ?>" /></span>
1556
			</label>
1557
1558
	<?php
1559
			endif; // !$bulk
1560
		endif; // page-attributes
1561
	?>
1562
1563
	<?php if ( 0 < count( get_page_templates( null, $screen->post_type ) ) ) : ?>
1564
		<label>
1565
			<span class="title"><?php _e( 'Template' ); ?></span>
1566
			<select name="page_template">
1567
<?php	if ( $bulk ) : ?>
1568
				<option value="-1"><?php _e( '&mdash; No Change &mdash;' ); ?></option>
1569
<?php	endif; // $bulk ?>
1570
                <?php
1571
				/** This filter is documented in wp-admin/includes/meta-boxes.php */
1572
				$default_title = apply_filters( 'default_page_template_title',  __( 'Default Template' ), 'quick-edit' );
1573
                ?>
1574
				<option value="default"><?php echo esc_html( $default_title ); ?></option>
1575
				<?php page_template_dropdown( '', $screen->post_type ) ?>
1576
			</select>
1577
		</label>
1578
	<?php endif; ?>
1579
1580
	<?php if ( count( $flat_taxonomies ) && !$bulk ) : ?>
1581
1582
	<?php foreach ( $flat_taxonomies as $taxonomy ) : ?>
1583
		<?php if ( current_user_can( $taxonomy->cap->assign_terms ) ) :
1584
			$taxonomy_name = esc_attr( $taxonomy->name );
1585
1586
			?>
1587
			<label class="inline-edit-tags">
1588
				<span class="title"><?php echo esc_html( $taxonomy->labels->name ) ?></span>
1589
				<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>
1590
			</label>
1591
		<?php endif; ?>
1592
1593
	<?php endforeach; //$flat_taxonomies as $taxonomy ?>
1594
1595
	<?php endif; // count( $flat_taxonomies ) && !$bulk  ?>
1596
1597
	<?php if ( post_type_supports( $screen->post_type, 'comments' ) || post_type_supports( $screen->post_type, 'trackbacks' ) ) :
1598
		if ( $bulk ) : ?>
1599
1600
			<div class="inline-edit-group wp-clearfix">
1601 View Code Duplication
		<?php if ( post_type_supports( $screen->post_type, 'comments' ) ) : ?>
1602
			<label class="alignleft">
1603
				<span class="title"><?php _e( 'Comments' ); ?></span>
1604
				<select name="comment_status">
1605
					<option value=""><?php _e( '&mdash; No Change &mdash;' ); ?></option>
1606
					<option value="open"><?php _e( 'Allow' ); ?></option>
1607
					<option value="closed"><?php _e( 'Do not allow' ); ?></option>
1608
				</select>
1609
			</label>
1610
		<?php endif; if ( post_type_supports( $screen->post_type, 'trackbacks' ) ) : ?>
1611
			<label class="alignright">
1612
				<span class="title"><?php _e( 'Pings' ); ?></span>
1613
				<select name="ping_status">
1614
					<option value=""><?php _e( '&mdash; No Change &mdash;' ); ?></option>
1615
					<option value="open"><?php _e( 'Allow' ); ?></option>
1616
					<option value="closed"><?php _e( 'Do not allow' ); ?></option>
1617
				</select>
1618
			</label>
1619
		<?php endif; ?>
1620
			</div>
1621
1622 View Code Duplication
	<?php else : // $bulk ?>
1623
1624
			<div class="inline-edit-group wp-clearfix">
1625
			<?php if ( post_type_supports( $screen->post_type, 'comments' ) ) : ?>
1626
				<label class="alignleft">
1627
					<input type="checkbox" name="comment_status" value="open" />
1628
					<span class="checkbox-title"><?php _e( 'Allow Comments' ); ?></span>
1629
				</label>
1630
			<?php endif; if ( post_type_supports( $screen->post_type, 'trackbacks' ) ) : ?>
1631
				<label class="alignleft">
1632
					<input type="checkbox" name="ping_status" value="open" />
1633
					<span class="checkbox-title"><?php _e( 'Allow Pings' ); ?></span>
1634
				</label>
1635
			<?php endif; ?>
1636
			</div>
1637
1638
	<?php endif; // $bulk
1639
	endif; // post_type_supports comments or pings ?>
1640
1641
			<div class="inline-edit-group wp-clearfix">
1642
				<label class="inline-edit-status alignleft">
1643
					<span class="title"><?php _e( 'Status' ); ?></span>
1644
					<select name="_status">
1645
	<?php if ( $bulk ) : ?>
1646
						<option value="-1"><?php _e( '&mdash; No Change &mdash;' ); ?></option>
1647
	<?php endif; // $bulk ?>
1648
					<?php if ( $can_publish ) : // Contributors only get "Unpublished" and "Pending Review" ?>
1649
						<option value="publish"><?php _e( 'Published' ); ?></option>
1650
						<option value="future"><?php _e( 'Scheduled' ); ?></option>
1651
	<?php if ( $bulk ) : ?>
1652
						<option value="private"><?php _e( 'Private' ) ?></option>
1653
	<?php endif; // $bulk ?>
1654
					<?php endif; ?>
1655
						<option value="pending"><?php _e( 'Pending Review' ); ?></option>
1656
						<option value="draft"><?php _e( 'Draft' ); ?></option>
1657
					</select>
1658
				</label>
1659
1660
	<?php if ( 'post' === $screen->post_type && $can_publish && current_user_can( $post_type_object->cap->edit_others_posts ) ) : ?>
1661
1662
	<?php	if ( $bulk ) : ?>
1663
1664
				<label class="alignright">
1665
					<span class="title"><?php _e( 'Sticky' ); ?></span>
1666
					<select name="sticky">
1667
						<option value="-1"><?php _e( '&mdash; No Change &mdash;' ); ?></option>
1668
						<option value="sticky"><?php _e( 'Sticky' ); ?></option>
1669
						<option value="unsticky"><?php _e( 'Not Sticky' ); ?></option>
1670
					</select>
1671
				</label>
1672
1673
	<?php	else : // $bulk ?>
1674
1675
				<label class="alignleft">
1676
					<input type="checkbox" name="sticky" value="sticky" />
1677
					<span class="checkbox-title"><?php _e( 'Make this post sticky' ); ?></span>
1678
				</label>
1679
1680
	<?php	endif; // $bulk ?>
1681
1682
	<?php endif; // 'post' && $can_publish && current_user_can( 'edit_others_cap' ) ?>
1683
1684
			</div>
1685
1686
	<?php
1687
1688
	if ( $bulk && current_theme_supports( 'post-formats' ) && post_type_supports( $screen->post_type, 'post-formats' ) ) {
1689
		$post_formats = get_theme_support( 'post-formats' );
1690
1691
		?>
1692
		<label class="alignleft">
1693
		<span class="title"><?php _ex( 'Format', 'post format' ); ?></span>
1694
		<select name="post_format">
1695
			<option value="-1"><?php _e( '&mdash; No Change &mdash;' ); ?></option>
1696
			<option value="0"><?php echo get_post_format_string( 'standard' ); ?></option>
1697
			<?php
1698
			if ( is_array( $post_formats[0] ) ) {
1699
				foreach ( $post_formats[0] as $format ) {
1700
					?>
1701
					<option value="<?php echo esc_attr( $format ); ?>"><?php echo esc_html( get_post_format_string( $format ) ); ?></option>
1702
					<?php
1703
				}
1704
			}
1705
			?>
1706
		</select></label>
1707
	<?php
1708
1709
	}
1710
1711
	?>
1712
1713
		</div></fieldset>
1714
1715
	<?php
1716
		list( $columns ) = $this->get_column_info();
1717
1718
		foreach ( $columns as $column_name => $column_display_name ) {
1719
			if ( isset( $core_columns[$column_name] ) )
1720
				continue;
1721
1722
			if ( $bulk ) {
1723
1724
				/**
1725
				 * Fires once for each column in Bulk Edit mode.
1726
				 *
1727
				 * @since 2.7.0
1728
				 *
1729
				 * @param string  $column_name Name of the column to edit.
1730
				 * @param WP_Post $post_type   The post type slug.
1731
				 */
1732
				do_action( 'bulk_edit_custom_box', $column_name, $screen->post_type );
1733
			} else {
1734
1735
				/**
1736
				 * Fires once for each column in Quick Edit mode.
1737
				 *
1738
				 * @since 2.7.0
1739
				 *
1740
				 * @param string $column_name Name of the column to edit.
1741
				 * @param string $post_type   The post type slug.
1742
				 */
1743
				do_action( 'quick_edit_custom_box', $column_name, $screen->post_type );
1744
			}
1745
1746
		}
1747
	?>
1748
		<p class="submit inline-edit-save">
1749
			<button type="button" class="button cancel alignleft"><?php _e( 'Cancel' ); ?></button>
1750
			<?php if ( ! $bulk ) {
1751
				wp_nonce_field( 'inlineeditnonce', '_inline_edit', false );
1752
				?>
1753
				<button type="button" class="button button-primary save alignright"><?php _e( 'Update' ); ?></button>
1754
				<span class="spinner"></span>
1755
			<?php } else {
1756
				submit_button( __( 'Update' ), 'primary alignright', 'bulk_edit', false );
1757
			} ?>
1758
			<input type="hidden" name="post_view" value="<?php echo esc_attr( $m ); ?>" />
1759
			<input type="hidden" name="screen" value="<?php echo esc_attr( $screen->id ); ?>" />
1760
			<?php if ( ! $bulk && ! post_type_supports( $screen->post_type, 'author' ) ) { ?>
1761
				<input type="hidden" name="post_author" value="<?php echo esc_attr( $post->post_author ); ?>" />
1762
			<?php } ?>
1763
			<span class="error" style="display:none"></span>
1764
			<br class="clear" />
1765
		</p>
1766
		</td></tr>
1767
	<?php
1768
		$bulk++;
1769
		}
1770
?>
1771
		</tbody></table></form>
1772
<?php
1773
	}
1774
}
1775