WP_Media_List_Table   D
last analyzed

Complexity

Total Complexity 112

Size/Duplication

Total Lines 765
Duplicated Lines 8.37 %

Coupling/Cohesion

Components 2
Dependencies 3

Importance

Changes 0
Metric Value
dl 64
loc 765
rs 4
c 0
b 0
f 0
wmc 112
lcom 2
cbo 3

24 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 13 3
A ajax_user_can() 0 3 1
A prepare_items() 0 15 3
D get_views() 0 43 10
A get_bulk_actions() 0 18 4
B current_action() 0 12 7
A has_items() 0 3 1
A no_items() 0 3 1
B views() 0 45 5
B get_columns() 10 51 6
A get_sortable_columns() 9 9 1
A column_cb() 0 8 2
B column_title() 0 38 5
A column_author() 0 6 1
A column_desc() 0 3 2
A column_date() 0 19 4
A column_comments() 0 13 2
C column_default() 9 46 7
C display_rows() 0 25 7
A get_default_primary_column_name() 0 3 1
A handle_row_actions() 0 8 2
C column_parent() 0 52 10
D _get_row_actions() 36 116 20
C extra_tablenav() 0 24 7

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_Media_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_Media_List_Table, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * List Table API: WP_Media_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 media items in a list table.
12
 *
13
 * @since 3.1.0
14
 * @access private
15
 *
16
 * @see WP_List_Table
17
 */
18
class WP_Media_List_Table extends WP_List_Table {
19
	/**
20
	 * Holds the number of pending comments for each post.
21
	 *
22
	 * @since 4.4.0
23
	 * @var array
24
	 * @access protected
25
	 */
26
	protected $comment_pending_count = array();
27
28
	private $detached;
29
30
	private $is_trash;
31
32
	/**
33
	 * Constructor.
34
	 *
35
	 * @since 3.1.0
36
	 * @access public
37
	 *
38
	 * @see WP_List_Table::__construct() for more information on default arguments.
39
	 *
40
	 * @param array $args An associative array of arguments.
41
	 */
42
	public function __construct( $args = array() ) {
43
		$this->detached = ( isset( $_REQUEST['attachment-filter'] ) && 'detached' === $_REQUEST['attachment-filter'] );
44
45
		$this->modes = array(
46
			'list' => __( 'List View' ),
47
			'grid' => __( 'Grid View' )
48
		);
49
50
		parent::__construct( array(
51
			'plural' => 'media',
52
			'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
53
		) );
54
	}
55
56
	/**
57
	 *
58
	 * @return bool
59
	 */
60
	public function ajax_user_can() {
61
		return current_user_can('upload_files');
62
	}
63
64
	/**
65
	 *
66
	 * @global WP_Query $wp_query
67
	 * @global array    $post_mime_types
68
	 * @global array    $avail_post_mime_types
69
	 * @global string   $mode
70
	 */
71
	public function prepare_items() {
72
		global $wp_query, $post_mime_types, $avail_post_mime_types, $mode;
73
74
		list( $post_mime_types, $avail_post_mime_types ) = wp_edit_attachments_query( $_REQUEST );
75
76
 		$this->is_trash = isset( $_REQUEST['attachment-filter'] ) && 'trash' === $_REQUEST['attachment-filter'];
77
78
 		$mode = empty( $_REQUEST['mode'] ) ? 'list' : $_REQUEST['mode'];
79
80
		$this->set_pagination_args( array(
81
			'total_items' => $wp_query->found_posts,
82
			'total_pages' => $wp_query->max_num_pages,
83
			'per_page' => $wp_query->query_vars['posts_per_page'],
84
		) );
85
	}
86
87
	/**
88
	 * @global array $post_mime_types
89
	 * @global array $avail_post_mime_types
90
	 * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,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...
91
	 */
92
	protected function get_views() {
93
		global $post_mime_types, $avail_post_mime_types;
94
95
		$type_links = array();
96
97
		$filter = empty( $_GET['attachment-filter'] ) ? '' : $_GET['attachment-filter'];
98
99
		$type_links['all'] = sprintf(
100
			'<option value=""%s>%s</option>',
101
			selected( $filter, true, false ),
102
			__( 'All media items' )
103
		);
104
105
		foreach ( $post_mime_types as $mime_type => $label ) {
106
			if ( ! wp_match_mime_types( $mime_type, $avail_post_mime_types ) ) {
107
				continue;
108
			}
109
110
			$selected = selected(
111
				$filter && 0 === strpos( $filter, 'post_mime_type:' ) &&
112
					wp_match_mime_types( $mime_type, str_replace( 'post_mime_type:', '', $filter ) ),
113
				true,
114
				false
115
			);
116
117
			$type_links[$mime_type] = sprintf(
118
				'<option value="post_mime_type:%s"%s>%s</option>',
119
				esc_attr( $mime_type ),
120
				$selected,
121
				$label[0]
122
			);
123
		}
124
		$type_links['detached'] = '<option value="detached"' . ( $this->detached ? ' selected="selected"' : '' ) . '>' . __( 'Unattached' ) . '</option>';
125
126
		if ( $this->is_trash || ( defined( 'MEDIA_TRASH') && MEDIA_TRASH ) ) {
127
			$type_links['trash'] = sprintf(
128
				'<option value="trash"%s>%s</option>',
129
				selected( 'trash' === $filter, true, false ),
130
				_x( 'Trash', 'attachment filter' )
131
			);
132
		}
133
		return $type_links;
134
	}
135
136
	/**
137
	 *
138
	 * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,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...
139
	 */
140
	protected function get_bulk_actions() {
141
		$actions = array();
142
		if ( MEDIA_TRASH ) {
143
			if ( $this->is_trash ) {
144
				$actions['untrash'] = __( 'Restore' );
145
				$actions['delete'] = __( 'Delete Permanently' );
146
			} else {
147
				$actions['trash'] = _x( 'Trash', 'verb' );
148
			}
149
		} else {
150
			$actions['delete'] = __( 'Delete Permanently' );
151
		}
152
153
		if ( $this->detached )
154
			$actions['attach'] = __( 'Attach' );
155
156
		return $actions;
157
	}
158
159
	/**
160
	 * @param string $which
161
	 */
162
	protected function extra_tablenav( $which ) {
163
		if ( 'bar' !== $which ) {
164
			return;
165
		}
166
?>
167
		<div class="actions">
168
<?php
169
		if ( ! is_singular() ) {
170
			if ( ! $this->is_trash ) {
171
				$this->months_dropdown( 'attachment' );
172
			}
173
174
			/** This action is documented in wp-admin/includes/class-wp-posts-list-table.php */
175
			do_action( 'restrict_manage_posts', $this->screen->post_type, $which );
176
177
			submit_button( __( 'Filter' ), '', 'filter_action', false, array( 'id' => 'post-query-submit' ) );
178
		}
179
180
		if ( $this->is_trash && current_user_can( 'edit_others_posts' ) && $this->has_items() ) {
181
			submit_button( __( 'Empty Trash' ), 'apply', 'delete_all', false );
182
		} ?>
183
		</div>
184
<?php
185
	}
186
187
	/**
188
	 *
189
	 * @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...
190
	 */
191
	public function current_action() {
192
		if ( isset( $_REQUEST['found_post_id'] ) && isset( $_REQUEST['media'] ) )
193
			return 'attach';
194
195
		if ( isset( $_REQUEST['parent_post_id'] ) && isset( $_REQUEST['media'] ) )
196
			return 'detach';
197
198
		if ( isset( $_REQUEST['delete_all'] ) || isset( $_REQUEST['delete_all2'] ) )
199
			return 'delete_all';
200
201
		return parent::current_action();
202
	}
203
204
	/**
205
	 *
206
	 * @return bool
207
	 */
208
	public function has_items() {
209
		return have_posts();
210
	}
211
212
	/**
213
	 * @access public
214
	 */
215
	public function no_items() {
216
		_e( 'No media files found.' );
217
	}
218
219
	/**
220
	 * Override parent views so we can use the filter bar display.
221
	 *
222
	 * @global string $mode List table view mode.
223
	 */
224
	public function views() {
225
		global $mode;
226
227
		$views = $this->get_views();
228
229
		$this->screen->render_screen_reader_content( 'heading_views' );
230
?>
231
<div class="wp-filter">
232
	<div class="filter-items">
233
		<?php $this->view_switcher( $mode ); ?>
234
235
		<label for="attachment-filter" class="screen-reader-text"><?php _e( 'Filter by type' ); ?></label>
236
		<select class="attachment-filters" name="attachment-filter" id="attachment-filter">
237
			<?php
238
			if ( ! empty( $views ) ) {
239
				foreach ( $views as $class => $view ) {
240
					echo "\t$view\n";
241
				}
242
			}
243
			?>
244
		</select>
245
246
<?php
247
		$this->extra_tablenav( 'bar' );
248
249
		/** This filter is documented in wp-admin/inclues/class-wp-list-table.php */
250
		$views = apply_filters( "views_{$this->screen->id}", array() );
251
252
		// Back compat for pre-4.0 view links.
253
		if ( ! empty( $views ) ) {
254
			echo '<ul class="filter-links">';
255
			foreach ( $views as $class => $view ) {
256
				echo "<li class='$class'>$view</li>";
257
			}
258
			echo '</ul>';
259
		}
260
?>
261
	</div>
262
263
	<div class="search-form">
264
		<label for="media-search-input" class="screen-reader-text"><?php esc_html_e( 'Search Media' ); ?></label>
265
		<input type="search" placeholder="<?php esc_attr_e( 'Search media items...' ) ?>" id="media-search-input" class="search" name="s" value="<?php _admin_search_query(); ?>"></div>
266
	</div>
267
	<?php
268
	}
269
270
	/**
271
	 *
272
	 * @return array
273
	 */
274
	public function get_columns() {
275
		$posts_columns = array();
276
		$posts_columns['cb'] = '<input type="checkbox" />';
277
		/* translators: column name */
278
		$posts_columns['title'] = _x( 'File', 'column name' );
279
		$posts_columns['author'] = __( 'Author' );
280
281
		$taxonomies = get_taxonomies_for_attachments( 'objects' );
282
		$taxonomies = wp_filter_object_list( $taxonomies, array( 'show_admin_column' => true ), 'and', 'name' );
283
284
		/**
285
		 * Filters the taxonomy columns for attachments in the Media list table.
286
		 *
287
		 * @since 3.5.0
288
		 *
289
		 * @param array  $taxonomies An array of registered taxonomies to show for attachments.
290
		 * @param string $post_type  The post type. Default 'attachment'.
291
		 */
292
		$taxonomies = apply_filters( 'manage_taxonomies_for_attachment_columns', $taxonomies, 'attachment' );
293
		$taxonomies = array_filter( $taxonomies, 'taxonomy_exists' );
294
295 View Code Duplication
		foreach ( $taxonomies as $taxonomy ) {
296
			if ( 'category' === $taxonomy ) {
297
				$column_key = 'categories';
298
			} elseif ( 'post_tag' === $taxonomy ) {
299
				$column_key = 'tags';
300
			} else {
301
				$column_key = 'taxonomy-' . $taxonomy;
302
			}
303
			$posts_columns[ $column_key ] = get_taxonomy( $taxonomy )->labels->name;
304
		}
305
306
		/* translators: column name */
307
		if ( !$this->detached ) {
308
			$posts_columns['parent'] = _x( 'Uploaded to', 'column name' );
309
			if ( post_type_supports( 'attachment', 'comments' ) )
310
				$posts_columns['comments'] = '<span class="vers comment-grey-bubble" title="' . esc_attr__( 'Comments' ) . '"><span class="screen-reader-text">' . __( 'Comments' ) . '</span></span>';
311
		}
312
		/* translators: column name */
313
		$posts_columns['date'] = _x( 'Date', 'column name' );
314
		/**
315
		 * Filters the Media list table columns.
316
		 *
317
		 * @since 2.5.0
318
		 *
319
		 * @param array $posts_columns An array of columns displayed in the Media list table.
320
		 * @param bool  $detached      Whether the list table contains media not attached
321
		 *                             to any posts. Default true.
322
		 */
323
		return apply_filters( 'manage_media_columns', $posts_columns, $this->detached );
324
	}
325
326
	/**
327
	 *
328
	 * @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...
329
	 */
330 View Code Duplication
	protected function get_sortable_columns() {
331
		return array(
332
			'title'    => 'title',
333
			'author'   => 'author',
334
			'parent'   => 'parent',
335
			'comments' => 'comment_count',
336
			'date'     => array( 'date', true ),
337
		);
338
	}
339
340
	/**
341
	 * Handles the checkbox column output.
342
	 *
343
	 * @since 4.3.0
344
	 * @access public
345
	 *
346
	 * @param WP_Post $post The current WP_Post object.
347
	 */
348
	public function column_cb( $post ) {
349
		if ( current_user_can( 'edit_post', $post->ID ) ) { ?>
350
			<label class="screen-reader-text" for="cb-select-<?php echo $post->ID; ?>"><?php
351
				echo sprintf( __( 'Select %s' ), _draft_or_post_title() );
352
			?></label>
353
			<input type="checkbox" name="media[]" id="cb-select-<?php echo $post->ID; ?>" value="<?php echo $post->ID; ?>" />
354
		<?php }
355
	}
356
357
	/**
358
	 * Handles the title column output.
359
	 *
360
	 * @since 4.3.0
361
	 * @access public
362
	 *
363
	 * @param WP_Post $post The current WP_Post object.
364
	 */
365
	public function column_title( $post ) {
366
		list( $mime ) = explode( '/', $post->post_mime_type );
367
368
		$title = _draft_or_post_title();
369
		$thumb = wp_get_attachment_image( $post->ID, array( 60, 60 ), true, array( 'alt' => '' ) );
370
		$link_start = $link_end = '';
371
372
		if ( current_user_can( 'edit_post', $post->ID ) && ! $this->is_trash ) {
373
			$link_start = sprintf(
374
				'<a href="%s" aria-label="%s">',
375
				get_edit_post_link( $post->ID ),
376
				/* translators: %s: attachment title */
377
				esc_attr( sprintf( __( '&#8220;%s&#8221; (Edit)' ), $title ) )
378
			);
379
			$link_end = '</a>';
380
		}
381
382
		$class = $thumb ? ' class="has-media-icon"' : '';
383
		?>
384
		<strong<?php echo $class; ?>>
385
			<?php
386
			echo $link_start;
387
			if ( $thumb ) : ?>
388
				<span class="media-icon <?php echo sanitize_html_class( $mime . '-icon' ); ?>"><?php echo $thumb; ?></span>
389
			<?php endif;
390
			echo $title . $link_end;
391
			_media_states( $post );
392
			?>
393
		</strong>
394
		<p class="filename">
395
			<span class="screen-reader-text"><?php _e( 'File name:' ); ?> </span>
396
			<?php
397
			$file = get_attached_file( $post->ID );
398
			echo esc_html( wp_basename( $file ) );
0 ignored issues
show
Security Bug introduced by
It seems like $file defined by get_attached_file($post->ID) on line 397 can also be of type false; however, wp_basename() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
399
			?>
400
		</p>
401
		<?php
402
	}
403
404
	/**
405
	 * Handles the author column output.
406
	 *
407
	 * @since 4.3.0
408
	 * @access public
409
	 *
410
	 * @param WP_Post $post The current WP_Post object.
411
	 */
412
	public function column_author( $post ) {
0 ignored issues
show
Unused Code introduced by
The parameter $post is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
413
		printf( '<a href="%s">%s</a>',
414
			esc_url( add_query_arg( array( 'author' => get_the_author_meta('ID') ), 'upload.php' ) ),
415
			get_the_author()
416
		);
417
	}
418
419
	/**
420
	 * Handles the description column output.
421
	 *
422
	 * @since 4.3.0
423
	 * @access public
424
	 *
425
	 * @param WP_Post $post The current WP_Post object.
426
	 */
427
	public function column_desc( $post ) {
428
		echo has_excerpt() ? $post->post_excerpt : '';
429
	}
430
431
	/**
432
	 * Handles the date column output.
433
	 *
434
	 * @since 4.3.0
435
	 * @access public
436
	 *
437
	 * @param WP_Post $post The current WP_Post object.
438
	 */
439
	public function column_date( $post ) {
440
		if ( '0000-00-00 00:00:00' === $post->post_date ) {
441
			$h_time = __( 'Unpublished' );
442
		} else {
443
			$m_time = $post->post_date;
444
			$time = get_post_time( 'G', true, $post, false );
445
			if ( ( abs( $t_diff = time() - $time ) ) < DAY_IN_SECONDS ) {
446
				if ( $t_diff < 0 ) {
447
					$h_time = sprintf( __( '%s from now' ), human_time_diff( $time ) );
448
				} else {
449
					$h_time = sprintf( __( '%s ago' ), human_time_diff( $time ) );
450
				}
451
			} else {
452
				$h_time = mysql2date( __( 'Y/m/d' ), $m_time );
453
			}
454
		}
455
456
		echo $h_time;
457
	}
458
459
	/**
460
	 * Handles the parent column output.
461
	 *
462
	 * @since 4.3.0
463
	 * @access public
464
	 *
465
	 * @param WP_Post $post The current WP_Post object.
466
	 */
467
	public function column_parent( $post ) {
468
		$user_can_edit = current_user_can( 'edit_post', $post->ID );
469
470
		if ( $post->post_parent > 0 ) {
471
			$parent = get_post( $post->post_parent );
472
		} else {
473
			$parent = false;
474
		}
475
476
		if ( $parent ) {
477
			$title = _draft_or_post_title( $post->post_parent );
478
			$parent_type = get_post_type_object( $parent->post_type );
479
480
			if ( $parent_type && $parent_type->show_ui && current_user_can( 'edit_post', $post->post_parent ) ) {
481
?>
482
				<strong><a href="<?php echo get_edit_post_link( $post->post_parent ); ?>">
483
					<?php echo $title ?></a></strong><?php
484
			} elseif ( $parent_type && current_user_can( 'read_post', $post->post_parent ) ) {
485
?>
486
				<strong><?php echo $title ?></strong><?php
487
			} else {
488
				_e( '(Private post)' );
489
			}
490
491
			if ( $user_can_edit ):
492
				$detach_url = add_query_arg( array(
493
					'parent_post_id' => $post->post_parent,
494
					'media[]' => $post->ID,
495
					'_wpnonce' => wp_create_nonce( 'bulk-' . $this->_args['plural'] )
496
				), 'upload.php' );
497
				printf(
498
					'<br /><a href="%s" class="hide-if-no-js detach-from-parent" aria-label="%s">%s</a>',
499
					$detach_url,
500
					/* translators: %s: title of the post the attachment is attached to */
501
					esc_attr( sprintf( __( 'Detach from &#8220;%s&#8221;' ), $title ) ),
502
					__( 'Detach' )
503
				);
504
			endif;
505
		} else {
506
			_e( '(Unattached)' ); ?>
507
			<?php if ( $user_can_edit ) {
508
				$title = _draft_or_post_title( $post->post_parent );
509
				printf(
510
					'<br /><a href="#the-list" onclick="findPosts.open( \'media[]\', \'%s\' ); return false;" class="hide-if-no-js aria-button-if-js" aria-label="%s">%s</a>',
511
					$post->ID,
512
					/* translators: %s: attachment title */
513
					esc_attr( sprintf( __( 'Attach &#8220;%s&#8221; to existing content' ), $title ) ),
514
					__( 'Attach' )
515
				);
516
			}
517
		}
518
	}
519
520
	/**
521
	 * Handles the comments column output.
522
	 *
523
	 * @since 4.3.0
524
	 * @access public
525
	 *
526
	 * @param WP_Post $post The current WP_Post object.
527
	 */
528
	public function column_comments( $post ) {
529
		echo '<div class="post-com-count-wrapper">';
530
531
		if ( isset( $this->comment_pending_count[ $post->ID ] ) ) {
532
			$pending_comments = $this->comment_pending_count[ $post->ID ];
533
		} else {
534
			$pending_comments = get_pending_comments_num( $post->ID );
535
		}
536
537
		$this->comments_bubble( $post->ID, $pending_comments );
538
539
		echo '</div>';
540
	}
541
542
	/**
543
	 * Handles output for the default column.
544
	 *
545
	 * @since 4.3.0
546
	 * @access public
547
	 *
548
	 * @param WP_Post $post        The current WP_Post object.
549
	 * @param string  $column_name Current column name.
550
	 */
551
	public function column_default( $post, $column_name ) {
552 View Code Duplication
		if ( 'categories' === $column_name ) {
553
			$taxonomy = 'category';
554
		} elseif ( 'tags' === $column_name ) {
555
			$taxonomy = 'post_tag';
556
		} elseif ( 0 === strpos( $column_name, 'taxonomy-' ) ) {
557
			$taxonomy = substr( $column_name, 9 );
558
		} else {
559
			$taxonomy = false;
560
		}
561
562
		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...
563
			$terms = get_the_terms( $post->ID, $taxonomy );
564
			if ( is_array( $terms ) ) {
565
				$out = array();
566
				foreach ( $terms as $t ) {
567
					$posts_in_term_qv = array();
568
					$posts_in_term_qv['taxonomy'] = $taxonomy;
569
					$posts_in_term_qv['term'] = $t->slug;
570
571
					$out[] = sprintf( '<a href="%s">%s</a>',
572
						esc_url( add_query_arg( $posts_in_term_qv, 'upload.php' ) ),
573
						esc_html( sanitize_term_field( 'name', $t->name, $t->term_id, $taxonomy, 'display' ) )
574
					);
575
				}
576
				/* translators: used between list items, there is a space after the comma */
577
				echo join( __( ', ' ), $out );
578
			} else {
579
				echo '<span aria-hidden="true">&#8212;</span><span class="screen-reader-text">' . get_taxonomy( $taxonomy )->labels->no_terms . '</span>';
580
			}
581
582
			return;
583
		}
584
585
		/**
586
		 * Fires for each custom column in the Media list table.
587
		 *
588
		 * Custom columns are registered using the {@see 'manage_media_columns'} filter.
589
		 *
590
		 * @since 2.5.0
591
		 *
592
		 * @param string $column_name Name of the custom column.
593
		 * @param int    $post_id     Attachment ID.
594
		 */
595
		do_action( 'manage_media_custom_column', $column_name, $post->ID );
596
	}
597
598
	/**
599
	 *
600
	 * @global WP_Post $post
601
	 */
602
	public function display_rows() {
603
		global $post, $wp_query;
604
605
		$post_ids = wp_list_pluck( $wp_query->posts, 'ID' );
606
		reset( $wp_query->posts );
607
608
		$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...
609
610
		add_filter( 'the_title','esc_html' );
611
612
		while ( have_posts() ) : the_post();
613
			if (
614
				( $this->is_trash && $post->post_status != 'trash' )
615
				|| ( ! $this->is_trash && $post->post_status === 'trash' )
616
			) {
617
				continue;
618
			}
619
			$post_owner = ( get_current_user_id() == $post->post_author ) ? 'self' : 'other';
620
		?>
621
			<tr id="post-<?php echo $post->ID; ?>" class="<?php echo trim( ' author-' . $post_owner . ' status-' . $post->post_status ); ?>">
622
				<?php $this->single_row_columns( $post ); ?>
623
			</tr>
624
		<?php
625
		endwhile;
626
	}
627
628
	/**
629
	 * Gets the name of the default primary column.
630
	 *
631
	 * @since 4.3.0
632
	 * @access protected
633
	 *
634
	 * @return string Name of the default primary column, in this case, 'title'.
635
	 */
636
	protected function get_default_primary_column_name() {
637
		return 'title';
638
	}
639
640
	/**
641
	 * @param WP_Post $post
642
	 * @param string  $att_title
643
	 *
644
	 * @return array
645
	 */
646
	private function _get_row_actions( $post, $att_title ) {
647
		$actions = array();
648
649
		if ( $this->detached ) {
650 View Code Duplication
			if ( current_user_can( 'edit_post', $post->ID ) ) {
651
				$actions['edit'] = sprintf(
652
					'<a href="%s" aria-label="%s">%s</a>',
653
					get_edit_post_link( $post->ID ),
654
					/* translators: %s: attachment title */
655
					esc_attr( sprintf( __( 'Edit &#8220;%s&#8221;' ), $att_title ) ),
656
					__( 'Edit' )
657
				);
658
			}
659
			if ( current_user_can( 'delete_post', $post->ID ) ) {
660
				if ( EMPTY_TRASH_DAYS && MEDIA_TRASH ) {
661
					$actions['trash'] = sprintf(
662
						'<a href="%s" class="submitdelete aria-button-if-js" aria-label="%s">%s</a>',
663
						wp_nonce_url( "post.php?action=trash&amp;post=$post->ID", 'trash-post_' . $post->ID ),
664
						/* translators: %s: attachment title */
665
						esc_attr( sprintf( __( 'Move &#8220;%s&#8221; to the Trash' ), $att_title ) ),
666
						_x( 'Trash', 'verb' )
667
					);
668
				} else {
669
					$delete_ays = ! MEDIA_TRASH ? " onclick='return showNotice.warn();'" : '';
670
					$actions['delete'] = sprintf(
671
						'<a href="%s" class="submitdelete aria-button-if-js"%s aria-label="%s">%s</a>',
672
						wp_nonce_url( "post.php?action=delete&amp;post=$post->ID", 'delete-post_' . $post->ID ),
673
						$delete_ays,
674
						/* translators: %s: attachment title */
675
						esc_attr( sprintf( __( 'Delete &#8220;%s&#8221; permanently' ), $att_title ) ),
676
						__( 'Delete Permanently' )
677
					);
678
				}
679
			}
680
			$actions['view'] = sprintf(
681
				'<a href="%s" aria-label="%s" rel="bookmark">%s</a>',
682
				get_permalink( $post->ID ),
683
				/* translators: %s: attachment title */
684
				esc_attr( sprintf( __( 'View &#8220;%s&#8221;' ), $att_title ) ),
685
				__( 'View' )
686
			);
687
688 View Code Duplication
			if ( current_user_can( 'edit_post', $post->ID ) ) {
689
				$actions['attach'] = sprintf(
690
					'<a href="#the-list" onclick="findPosts.open( \'media[]\', \'%s\' ); return false;" class="hide-if-no-js aria-button-if-js" aria-label="%s">%s</a>',
691
					$post->ID,
692
					/* translators: %s: attachment title */
693
					esc_attr( sprintf( __( 'Attach &#8220;%s&#8221; to existing content' ), $att_title ) ),
694
					__( 'Attach' )
695
				);
696
			}
697
		}
698
		else {
699 View Code Duplication
			if ( current_user_can( 'edit_post', $post->ID ) && !$this->is_trash ) {
700
				$actions['edit'] = sprintf(
701
					'<a href="%s" aria-label="%s">%s</a>',
702
					get_edit_post_link( $post->ID ),
703
					/* translators: %s: attachment title */
704
					esc_attr( sprintf( __( 'Edit &#8220;%s&#8221;' ), $att_title ) ),
705
					__( 'Edit' )
706
				);
707
			}
708
			if ( current_user_can( 'delete_post', $post->ID ) ) {
709
				if ( $this->is_trash ) {
710
					$actions['untrash'] = sprintf(
711
						'<a href="%s" class="submitdelete aria-button-if-js" aria-label="%s">%s</a>',
712
						wp_nonce_url( "post.php?action=untrash&amp;post=$post->ID", 'untrash-post_' . $post->ID ),
713
						/* translators: %s: attachment title */
714
						esc_attr( sprintf( __( 'Restore &#8220;%s&#8221; from the Trash' ), $att_title ) ),
715
						__( 'Restore' )
716
					);
717 View Code Duplication
				} elseif ( EMPTY_TRASH_DAYS && MEDIA_TRASH ) {
718
					$actions['trash'] = sprintf(
719
						'<a href="%s" class="submitdelete aria-button-if-js" aria-label="%s">%s</a>',
720
						wp_nonce_url( "post.php?action=trash&amp;post=$post->ID", 'trash-post_' . $post->ID ),
721
						/* translators: %s: attachment title */
722
						esc_attr( sprintf( __( 'Move &#8220;%s&#8221; to the Trash' ), $att_title ) ),
723
						_x( 'Trash', 'verb' )
724
					);
725
				}
726
				if ( $this->is_trash || ! EMPTY_TRASH_DAYS || ! MEDIA_TRASH ) {
727
					$delete_ays = ( !$this->is_trash && !MEDIA_TRASH ) ? " onclick='return showNotice.warn();'" : '';
728
					$actions['delete'] = sprintf(
729
						'<a href="%s" class="submitdelete aria-button-if-js"%s aria-label="%s">%s</a>',
730
						wp_nonce_url( "post.php?action=delete&amp;post=$post->ID", 'delete-post_' . $post->ID ),
731
						$delete_ays,
732
						/* translators: %s: attachment title */
733
						esc_attr( sprintf( __( 'Delete &#8220;%s&#8221; permanently' ), $att_title ) ),
734
						__( 'Delete Permanently' )
735
					);
736
				}
737
			}
738
			if ( ! $this->is_trash ) {
739
				$actions['view'] = sprintf(
740
					'<a href="%s" aria-label="%s" rel="bookmark">%s</a>',
741
					get_permalink( $post->ID ),
742
					/* translators: %s: attachment title */
743
					esc_attr( sprintf( __( 'View &#8220;%s&#8221;' ), $att_title ) ),
744
					__( 'View' )
745
				);
746
			}
747
		}
748
749
		/**
750
		 * Filters the action links for each attachment in the Media list table.
751
		 *
752
		 * @since 2.8.0
753
		 *
754
		 * @param array   $actions  An array of action links for each attachment.
755
		 *                          Default 'Edit', 'Delete Permanently', 'View'.
756
		 * @param WP_Post $post     WP_Post object for the current attachment.
757
		 * @param bool    $detached Whether the list table contains media not attached
758
		 *                          to any posts. Default true.
759
		 */
760
		return apply_filters( 'media_row_actions', $actions, $post, $this->detached );
761
	}
762
763
	/**
764
	 * Generates and displays row action links.
765
	 *
766
	 * @since 4.3.0
767
	 * @access protected
768
	 *
769
	 * @param object $post        Attachment being acted upon.
770
	 * @param string $column_name Current column name.
771
	 * @param string $primary     Primary column name.
772
	 * @return string Row actions output for media attachments.
773
	 */
774
	protected function handle_row_actions( $post, $column_name, $primary ) {
775
		if ( $primary !== $column_name ) {
776
			return '';
777
		}
778
779
		$att_title = _draft_or_post_title();
780
		return $this->row_actions( $this->_get_row_actions( $post, $att_title ) );
781
	}
782
}
783