home *** CD-ROM | disk | FTP | other *** search
/ HTML Examples / WP.iso / wordpress / wp-admin / includes / class-wp-media-list-table.php < prev    next >
Encoding:
PHP Script  |  2017-07-26  |  22.0 KB  |  770 lines

  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.      */
  25.     protected $comment_pending_count = array();
  26.  
  27.     private $detached;
  28.  
  29.     private $is_trash;
  30.  
  31.     /**
  32.      * Constructor.
  33.      *
  34.      * @since 3.1.0
  35.      *
  36.      * @see WP_List_Table::__construct() for more information on default arguments.
  37.      *
  38.      * @param array $args An associative array of arguments.
  39.      */
  40.     public function __construct( $args = array() ) {
  41.         $this->detached = ( isset( $_REQUEST['attachment-filter'] ) && 'detached' === $_REQUEST['attachment-filter'] );
  42.  
  43.         $this->modes = array(
  44.             'list' => __( 'List View' ),
  45.             'grid' => __( 'Grid View' )
  46.         );
  47.  
  48.         parent::__construct( array(
  49.             'plural' => 'media',
  50.             'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
  51.         ) );
  52.     }
  53.  
  54.     /**
  55.      *
  56.      * @return bool
  57.      */
  58.     public function ajax_user_can() {
  59.         return current_user_can('upload_files');
  60.     }
  61.  
  62.     /**
  63.      *
  64.      * @global WP_Query $wp_query
  65.      * @global array    $post_mime_types
  66.      * @global array    $avail_post_mime_types
  67.      * @global string   $mode
  68.      */
  69.     public function prepare_items() {
  70.         global $wp_query, $post_mime_types, $avail_post_mime_types, $mode;
  71.  
  72.         list( $post_mime_types, $avail_post_mime_types ) = wp_edit_attachments_query( $_REQUEST );
  73.  
  74.          $this->is_trash = isset( $_REQUEST['attachment-filter'] ) && 'trash' === $_REQUEST['attachment-filter'];
  75.  
  76.          $mode = empty( $_REQUEST['mode'] ) ? 'list' : $_REQUEST['mode'];
  77.  
  78.         $this->set_pagination_args( array(
  79.             'total_items' => $wp_query->found_posts,
  80.             'total_pages' => $wp_query->max_num_pages,
  81.             'per_page' => $wp_query->query_vars['posts_per_page'],
  82.         ) );
  83.     }
  84.  
  85.     /**
  86.      * @global array $post_mime_types
  87.      * @global array $avail_post_mime_types
  88.      * @return array
  89.      */
  90.     protected function get_views() {
  91.         global $post_mime_types, $avail_post_mime_types;
  92.  
  93.         $type_links = array();
  94.  
  95.         $filter = empty( $_GET['attachment-filter'] ) ? '' : $_GET['attachment-filter'];
  96.  
  97.         $type_links['all'] = sprintf(
  98.             '<option value=""%s>%s</option>',
  99.             selected( $filter, true, false ),
  100.             __( 'All media items' )
  101.         );
  102.  
  103.         foreach ( $post_mime_types as $mime_type => $label ) {
  104.             if ( ! wp_match_mime_types( $mime_type, $avail_post_mime_types ) ) {
  105.                 continue;
  106.             }
  107.  
  108.             $selected = selected(
  109.                 $filter && 0 === strpos( $filter, 'post_mime_type:' ) &&
  110.                     wp_match_mime_types( $mime_type, str_replace( 'post_mime_type:', '', $filter ) ),
  111.                 true,
  112.                 false
  113.             );
  114.  
  115.             $type_links[$mime_type] = sprintf(
  116.                 '<option value="post_mime_type:%s"%s>%s</option>',
  117.                 esc_attr( $mime_type ),
  118.                 $selected,
  119.                 $label[0]
  120.             );
  121.         }
  122.         $type_links['detached'] = '<option value="detached"' . ( $this->detached ? ' selected="selected"' : '' ) . '>' . __( 'Unattached' ) . '</option>';
  123.  
  124.         if ( $this->is_trash || ( defined( 'MEDIA_TRASH') && MEDIA_TRASH ) ) {
  125.             $type_links['trash'] = sprintf(
  126.                 '<option value="trash"%s>%s</option>',
  127.                 selected( 'trash' === $filter, true, false ),
  128.                 _x( 'Trash', 'attachment filter' )
  129.             );
  130.         }
  131.         return $type_links;
  132.     }
  133.  
  134.     /**
  135.      *
  136.      * @return array
  137.      */
  138.     protected function get_bulk_actions() {
  139.         $actions = array();
  140.         if ( MEDIA_TRASH ) {
  141.             if ( $this->is_trash ) {
  142.                 $actions['untrash'] = __( 'Restore' );
  143.                 $actions['delete'] = __( 'Delete Permanently' );
  144.             } else {
  145.                 $actions['trash'] = _x( 'Trash', 'verb' );
  146.             }
  147.         } else {
  148.             $actions['delete'] = __( 'Delete Permanently' );
  149.         }
  150.  
  151.         if ( $this->detached )
  152.             $actions['attach'] = __( 'Attach' );
  153.  
  154.         return $actions;
  155.     }
  156.  
  157.     /**
  158.      * @param string $which
  159.      */
  160.     protected function extra_tablenav( $which ) {
  161.         if ( 'bar' !== $which ) {
  162.             return;
  163.         }
  164. ?>
  165.         <div class="actions">
  166. <?php
  167.         if ( ! is_singular() ) {
  168.             if ( ! $this->is_trash ) {
  169.                 $this->months_dropdown( 'attachment' );
  170.             }
  171.  
  172.             /** This action is documented in wp-admin/includes/class-wp-posts-list-table.php */
  173.             do_action( 'restrict_manage_posts', $this->screen->post_type, $which );
  174.  
  175.             submit_button( __( 'Filter' ), '', 'filter_action', false, array( 'id' => 'post-query-submit' ) );
  176.         }
  177.  
  178.         if ( $this->is_trash && current_user_can( 'edit_others_posts' ) && $this->has_items() ) {
  179.             submit_button( __( 'Empty Trash' ), 'apply', 'delete_all', false );
  180.         } ?>
  181.         </div>
  182. <?php
  183.     }
  184.  
  185.     /**
  186.      *
  187.      * @return string
  188.      */
  189.     public function current_action() {
  190.         if ( isset( $_REQUEST['found_post_id'] ) && isset( $_REQUEST['media'] ) )
  191.             return 'attach';
  192.  
  193.         if ( isset( $_REQUEST['parent_post_id'] ) && isset( $_REQUEST['media'] ) )
  194.             return 'detach';
  195.  
  196.         if ( isset( $_REQUEST['delete_all'] ) || isset( $_REQUEST['delete_all2'] ) )
  197.             return 'delete_all';
  198.  
  199.         return parent::current_action();
  200.     }
  201.  
  202.     /**
  203.      *
  204.      * @return bool
  205.      */
  206.     public function has_items() {
  207.         return have_posts();
  208.     }
  209.  
  210.     /**
  211.      */
  212.     public function no_items() {
  213.         _e( 'No media files found.' );
  214.     }
  215.  
  216.     /**
  217.      * Override parent views so we can use the filter bar display.
  218.      *
  219.      * @global string $mode List table view mode.
  220.      */
  221.     public function views() {
  222.         global $mode;
  223.  
  224.         $views = $this->get_views();
  225.  
  226.         $this->screen->render_screen_reader_content( 'heading_views' );
  227. ?>
  228. <div class="wp-filter">
  229.     <div class="filter-items">
  230.         <?php $this->view_switcher( $mode ); ?>
  231.  
  232.         <label for="attachment-filter" class="screen-reader-text"><?php _e( 'Filter by type' ); ?></label>
  233.         <select class="attachment-filters" name="attachment-filter" id="attachment-filter">
  234.             <?php
  235.             if ( ! empty( $views ) ) {
  236.                 foreach ( $views as $class => $view ) {
  237.                     echo "\t$view\n";
  238.                 }
  239.             }
  240.             ?>
  241.         </select>
  242.  
  243. <?php
  244.         $this->extra_tablenav( 'bar' );
  245.  
  246.         /** This filter is documented in wp-admin/inclues/class-wp-list-table.php */
  247.         $views = apply_filters( "views_{$this->screen->id}", array() );
  248.  
  249.         // Back compat for pre-4.0 view links.
  250.         if ( ! empty( $views ) ) {
  251.             echo '<ul class="filter-links">';
  252.             foreach ( $views as $class => $view ) {
  253.                 echo "<li class='$class'>$view</li>";
  254.             }
  255.             echo '</ul>';
  256.         }
  257. ?>
  258.     </div>
  259.  
  260.     <div class="search-form">
  261.         <label for="media-search-input" class="screen-reader-text"><?php esc_html_e( 'Search Media' ); ?></label>
  262.         <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>
  263.     </div>
  264.     <?php
  265.     }
  266.  
  267.     /**
  268.      *
  269.      * @return array
  270.      */
  271.     public function get_columns() {
  272.         $posts_columns = array();
  273.         $posts_columns['cb'] = '<input type="checkbox" />';
  274.         /* translators: column name */
  275.         $posts_columns['title'] = _x( 'File', 'column name' );
  276.         $posts_columns['author'] = __( 'Author' );
  277.  
  278.         $taxonomies = get_taxonomies_for_attachments( 'objects' );
  279.         $taxonomies = wp_filter_object_list( $taxonomies, array( 'show_admin_column' => true ), 'and', 'name' );
  280.  
  281.         /**
  282.          * Filters the taxonomy columns for attachments in the Media list table.
  283.          *
  284.          * @since 3.5.0
  285.          *
  286.          * @param array  $taxonomies An array of registered taxonomies to show for attachments.
  287.          * @param string $post_type  The post type. Default 'attachment'.
  288.          */
  289.         $taxonomies = apply_filters( 'manage_taxonomies_for_attachment_columns', $taxonomies, 'attachment' );
  290.         $taxonomies = array_filter( $taxonomies, 'taxonomy_exists' );
  291.  
  292.         foreach ( $taxonomies as $taxonomy ) {
  293.             if ( 'category' === $taxonomy ) {
  294.                 $column_key = 'categories';
  295.             } elseif ( 'post_tag' === $taxonomy ) {
  296.                 $column_key = 'tags';
  297.             } else {
  298.                 $column_key = 'taxonomy-' . $taxonomy;
  299.             }
  300.             $posts_columns[ $column_key ] = get_taxonomy( $taxonomy )->labels->name;
  301.         }
  302.  
  303.         /* translators: column name */
  304.         if ( !$this->detached ) {
  305.             $posts_columns['parent'] = _x( 'Uploaded to', 'column name' );
  306.             if ( post_type_supports( 'attachment', 'comments' ) )
  307.                 $posts_columns['comments'] = '<span class="vers comment-grey-bubble" title="' . esc_attr__( 'Comments' ) . '"><span class="screen-reader-text">' . __( 'Comments' ) . '</span></span>';
  308.         }
  309.         /* translators: column name */
  310.         $posts_columns['date'] = _x( 'Date', 'column name' );
  311.         /**
  312.          * Filters the Media list table columns.
  313.          *
  314.          * @since 2.5.0
  315.          *
  316.          * @param array $posts_columns An array of columns displayed in the Media list table.
  317.          * @param bool  $detached      Whether the list table contains media not attached
  318.          *                             to any posts. Default true.
  319.          */
  320.         return apply_filters( 'manage_media_columns', $posts_columns, $this->detached );
  321.     }
  322.  
  323.     /**
  324.      *
  325.      * @return array
  326.      */
  327.     protected function get_sortable_columns() {
  328.         return array(
  329.             'title'    => 'title',
  330.             'author'   => 'author',
  331.             'parent'   => 'parent',
  332.             'comments' => 'comment_count',
  333.             'date'     => array( 'date', true ),
  334.         );
  335.     }
  336.  
  337.     /**
  338.      * Handles the checkbox column output.
  339.      *
  340.      * @since 4.3.0
  341.      *
  342.      * @param WP_Post $post The current WP_Post object.
  343.      */
  344.     public function column_cb( $post ) {
  345.         if ( current_user_can( 'edit_post', $post->ID ) ) { ?>
  346.             <label class="screen-reader-text" for="cb-select-<?php echo $post->ID; ?>"><?php
  347.                 echo sprintf( __( 'Select %s' ), _draft_or_post_title() );
  348.             ?></label>
  349.             <input type="checkbox" name="media[]" id="cb-select-<?php echo $post->ID; ?>" value="<?php echo $post->ID; ?>" />
  350.         <?php }
  351.     }
  352.  
  353.     /**
  354.      * Handles the title column output.
  355.      *
  356.      * @since 4.3.0
  357.      *
  358.      * @param WP_Post $post The current WP_Post object.
  359.      */
  360.     public function column_title( $post ) {
  361.         list( $mime ) = explode( '/', $post->post_mime_type );
  362.  
  363.         $title = _draft_or_post_title();
  364.         $thumb = wp_get_attachment_image( $post->ID, array( 60, 60 ), true, array( 'alt' => '' ) );
  365.         $link_start = $link_end = '';
  366.  
  367.         if ( current_user_can( 'edit_post', $post->ID ) && ! $this->is_trash ) {
  368.             $link_start = sprintf(
  369.                 '<a href="%s" aria-label="%s">',
  370.                 get_edit_post_link( $post->ID ),
  371.                 /* translators: %s: attachment title */
  372.                 esc_attr( sprintf( __( '“%s” (Edit)' ), $title ) )
  373.             );
  374.             $link_end = '</a>';
  375.         }
  376.  
  377.         $class = $thumb ? ' class="has-media-icon"' : '';
  378.         ?>
  379.         <strong<?php echo $class; ?>>
  380.             <?php
  381.             echo $link_start;
  382.             if ( $thumb ) : ?>
  383.                 <span class="media-icon <?php echo sanitize_html_class( $mime . '-icon' ); ?>"><?php echo $thumb; ?></span>
  384.             <?php endif;
  385.             echo $title . $link_end;
  386.             _media_states( $post );
  387.             ?>
  388.         </strong>
  389.         <p class="filename">
  390.             <span class="screen-reader-text"><?php _e( 'File name:' ); ?> </span>
  391.             <?php
  392.             $file = get_attached_file( $post->ID );
  393.             echo esc_html( wp_basename( $file ) );
  394.             ?>
  395.         </p>
  396.         <?php
  397.     }
  398.  
  399.     /**
  400.      * Handles the author column output.
  401.      *
  402.      * @since 4.3.0
  403.      *
  404.      * @param WP_Post $post The current WP_Post object.
  405.      */
  406.     public function column_author( $post ) {
  407.         printf( '<a href="%s">%s</a>',
  408.             esc_url( add_query_arg( array( 'author' => get_the_author_meta('ID') ), 'upload.php' ) ),
  409.             get_the_author()
  410.         );
  411.     }
  412.  
  413.     /**
  414.      * Handles the description column output.
  415.      *
  416.      * @since 4.3.0
  417.      *
  418.      * @param WP_Post $post The current WP_Post object.
  419.      */
  420.     public function column_desc( $post ) {
  421.         echo has_excerpt() ? $post->post_excerpt : '';
  422.     }
  423.  
  424.     /**
  425.      * Handles the date column output.
  426.      *
  427.      * @since 4.3.0
  428.      *
  429.      * @param WP_Post $post The current WP_Post object.
  430.      */
  431.     public function column_date( $post ) {
  432.         if ( '0000-00-00 00:00:00' === $post->post_date ) {
  433.             $h_time = __( 'Unpublished' );
  434.         } else {
  435.             $m_time = $post->post_date;
  436.             $time = get_post_time( 'G', true, $post, false );
  437.             if ( ( abs( $t_diff = time() - $time ) ) < DAY_IN_SECONDS ) {
  438.                 if ( $t_diff < 0 ) {
  439.                     $h_time = sprintf( __( '%s from now' ), human_time_diff( $time ) );
  440.                 } else {
  441.                     $h_time = sprintf( __( '%s ago' ), human_time_diff( $time ) );
  442.                 }
  443.             } else {
  444.                 $h_time = mysql2date( __( 'Y/m/d' ), $m_time );
  445.             }
  446.         }
  447.  
  448.         echo $h_time;
  449.     }
  450.  
  451.     /**
  452.      * Handles the parent column output.
  453.      *
  454.      * @since 4.3.0
  455.      *
  456.      * @param WP_Post $post The current WP_Post object.
  457.      */
  458.     public function column_parent( $post ) {
  459.         $user_can_edit = current_user_can( 'edit_post', $post->ID );
  460.  
  461.         if ( $post->post_parent > 0 ) {
  462.             $parent = get_post( $post->post_parent );
  463.         } else {
  464.             $parent = false;
  465.         }
  466.  
  467.         if ( $parent ) {
  468.             $title = _draft_or_post_title( $post->post_parent );
  469.             $parent_type = get_post_type_object( $parent->post_type );
  470.  
  471.             if ( $parent_type && $parent_type->show_ui && current_user_can( 'edit_post', $post->post_parent ) ) {
  472. ?>
  473.                 <strong><a href="<?php echo get_edit_post_link( $post->post_parent ); ?>">
  474.                     <?php echo $title ?></a></strong><?php
  475.             } elseif ( $parent_type && current_user_can( 'read_post', $post->post_parent ) ) {
  476. ?>
  477.                 <strong><?php echo $title ?></strong><?php
  478.             } else {
  479.                 _e( '(Private post)' );
  480.             }
  481.  
  482.             if ( $user_can_edit ):
  483.                 $detach_url = add_query_arg( array(
  484.                     'parent_post_id' => $post->post_parent,
  485.                     'media[]' => $post->ID,
  486.                     '_wpnonce' => wp_create_nonce( 'bulk-' . $this->_args['plural'] )
  487.                 ), 'upload.php' );
  488.                 printf(
  489.                     '<br /><a href="%s" class="hide-if-no-js detach-from-parent" aria-label="%s">%s</a>',
  490.                     $detach_url,
  491.                     /* translators: %s: title of the post the attachment is attached to */
  492.                     esc_attr( sprintf( __( 'Detach from “%s”' ), $title ) ),
  493.                     __( 'Detach' )
  494.                 );
  495.             endif;
  496.         } else {
  497.             _e( '(Unattached)' ); ?>
  498.             <?php if ( $user_can_edit ) {
  499.                 $title = _draft_or_post_title( $post->post_parent );
  500.                 printf(
  501.                     '<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>',
  502.                     $post->ID,
  503.                     /* translators: %s: attachment title */
  504.                     esc_attr( sprintf( __( 'Attach “%s” to existing content' ), $title ) ),
  505.                     __( 'Attach' )
  506.                 );
  507.             }
  508.         }
  509.     }
  510.  
  511.     /**
  512.      * Handles the comments column output.
  513.      *
  514.      * @since 4.3.0
  515.      *
  516.      * @param WP_Post $post The current WP_Post object.
  517.      */
  518.     public function column_comments( $post ) {
  519.         echo '<div class="post-com-count-wrapper">';
  520.  
  521.         if ( isset( $this->comment_pending_count[ $post->ID ] ) ) {
  522.             $pending_comments = $this->comment_pending_count[ $post->ID ];
  523.         } else {
  524.             $pending_comments = get_pending_comments_num( $post->ID );
  525.         }
  526.  
  527.         $this->comments_bubble( $post->ID, $pending_comments );
  528.  
  529.         echo '</div>';
  530.     }
  531.  
  532.     /**
  533.      * Handles output for the default column.
  534.      *
  535.      * @since 4.3.0
  536.      *
  537.      * @param WP_Post $post        The current WP_Post object.
  538.      * @param string  $column_name Current column name.
  539.      */
  540.     public function column_default( $post, $column_name ) {
  541.         if ( 'categories' === $column_name ) {
  542.             $taxonomy = 'category';
  543.         } elseif ( 'tags' === $column_name ) {
  544.             $taxonomy = 'post_tag';
  545.         } elseif ( 0 === strpos( $column_name, 'taxonomy-' ) ) {
  546.             $taxonomy = substr( $column_name, 9 );
  547.         } else {
  548.             $taxonomy = false;
  549.         }
  550.  
  551.         if ( $taxonomy ) {
  552.             $terms = get_the_terms( $post->ID, $taxonomy );
  553.             if ( is_array( $terms ) ) {
  554.                 $out = array();
  555.                 foreach ( $terms as $t ) {
  556.                     $posts_in_term_qv = array();
  557.                     $posts_in_term_qv['taxonomy'] = $taxonomy;
  558.                     $posts_in_term_qv['term'] = $t->slug;
  559.  
  560.                     $out[] = sprintf( '<a href="%s">%s</a>',
  561.                         esc_url( add_query_arg( $posts_in_term_qv, 'upload.php' ) ),
  562.                         esc_html( sanitize_term_field( 'name', $t->name, $t->term_id, $taxonomy, 'display' ) )
  563.                     );
  564.                 }
  565.                 /* translators: used between list items, there is a space after the comma */
  566.                 echo join( __( ', ' ), $out );
  567.             } else {
  568.                 echo '<span aria-hidden="true">—</span><span class="screen-reader-text">' . get_taxonomy( $taxonomy )->labels->no_terms . '</span>';
  569.             }
  570.  
  571.             return;
  572.         }
  573.  
  574.         /**
  575.          * Fires for each custom column in the Media list table.
  576.          *
  577.          * Custom columns are registered using the {@see 'manage_media_columns'} filter.
  578.          *
  579.          * @since 2.5.0
  580.          *
  581.          * @param string $column_name Name of the custom column.
  582.          * @param int    $post_id     Attachment ID.
  583.          */
  584.         do_action( 'manage_media_custom_column', $column_name, $post->ID );
  585.     }
  586.  
  587.     /**
  588.      *
  589.      * @global WP_Post $post
  590.      */
  591.     public function display_rows() {
  592.         global $post, $wp_query;
  593.  
  594.         $post_ids = wp_list_pluck( $wp_query->posts, 'ID' );
  595.         reset( $wp_query->posts );
  596.  
  597.         $this->comment_pending_count = get_pending_comments_num( $post_ids );
  598.  
  599.         add_filter( 'the_title','esc_html' );
  600.  
  601.         while ( have_posts() ) : the_post();
  602.             if (
  603.                 ( $this->is_trash && $post->post_status != 'trash' )
  604.                 || ( ! $this->is_trash && $post->post_status === 'trash' )
  605.             ) {
  606.                 continue;
  607.             }
  608.             $post_owner = ( get_current_user_id() == $post->post_author ) ? 'self' : 'other';
  609.         ?>
  610.             <tr id="post-<?php echo $post->ID; ?>" class="<?php echo trim( ' author-' . $post_owner . ' status-' . $post->post_status ); ?>">
  611.                 <?php $this->single_row_columns( $post ); ?>
  612.             </tr>
  613.         <?php
  614.         endwhile;
  615.     }
  616.  
  617.     /**
  618.      * Gets the name of the default primary column.
  619.      *
  620.      * @since 4.3.0
  621.      *
  622.      * @return string Name of the default primary column, in this case, 'title'.
  623.      */
  624.     protected function get_default_primary_column_name() {
  625.         return 'title';
  626.     }
  627.  
  628.     /**
  629.      * @param WP_Post $post
  630.      * @param string  $att_title
  631.      *
  632.      * @return array
  633.      */
  634.     private function _get_row_actions( $post, $att_title ) {
  635.         $actions = array();
  636.  
  637.         if ( $this->detached ) {
  638.             if ( current_user_can( 'edit_post', $post->ID ) ) {
  639.                 $actions['edit'] = sprintf(
  640.                     '<a href="%s" aria-label="%s">%s</a>',
  641.                     get_edit_post_link( $post->ID ),
  642.                     /* translators: %s: attachment title */
  643.                     esc_attr( sprintf( __( 'Edit “%s”' ), $att_title ) ),
  644.                     __( 'Edit' )
  645.                 );
  646.             }
  647.             if ( current_user_can( 'delete_post', $post->ID ) ) {
  648.                 if ( EMPTY_TRASH_DAYS && MEDIA_TRASH ) {
  649.                     $actions['trash'] = sprintf(
  650.                         '<a href="%s" class="submitdelete aria-button-if-js" aria-label="%s">%s</a>',
  651.                         wp_nonce_url( "post.php?action=trash&post=$post->ID", 'trash-post_' . $post->ID ),
  652.                         /* translators: %s: attachment title */
  653.                         esc_attr( sprintf( __( 'Move “%s” to the Trash' ), $att_title ) ),
  654.                         _x( 'Trash', 'verb' )
  655.                     );
  656.                 } else {
  657.                     $delete_ays = ! MEDIA_TRASH ? " onclick='return showNotice.warn();'" : '';
  658.                     $actions['delete'] = sprintf(
  659.                         '<a href="%s" class="submitdelete aria-button-if-js"%s aria-label="%s">%s</a>',
  660.                         wp_nonce_url( "post.php?action=delete&post=$post->ID", 'delete-post_' . $post->ID ),
  661.                         $delete_ays,
  662.                         /* translators: %s: attachment title */
  663.                         esc_attr( sprintf( __( 'Delete “%s” permanently' ), $att_title ) ),
  664.                         __( 'Delete Permanently' )
  665.                     );
  666.                 }
  667.             }
  668.             $actions['view'] = sprintf(
  669.                 '<a href="%s" aria-label="%s" rel="bookmark">%s</a>',
  670.                 get_permalink( $post->ID ),
  671.                 /* translators: %s: attachment title */
  672.                 esc_attr( sprintf( __( 'View “%s”' ), $att_title ) ),
  673.                 __( 'View' )
  674.             );
  675.  
  676.             if ( current_user_can( 'edit_post', $post->ID ) ) {
  677.                 $actions['attach'] = sprintf(
  678.                     '<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>',
  679.                     $post->ID,
  680.                     /* translators: %s: attachment title */
  681.                     esc_attr( sprintf( __( 'Attach “%s” to existing content' ), $att_title ) ),
  682.                     __( 'Attach' )
  683.                 );
  684.             }
  685.         }
  686.         else {
  687.             if ( current_user_can( 'edit_post', $post->ID ) && !$this->is_trash ) {
  688.                 $actions['edit'] = sprintf(
  689.                     '<a href="%s" aria-label="%s">%s</a>',
  690.                     get_edit_post_link( $post->ID ),
  691.                     /* translators: %s: attachment title */
  692.                     esc_attr( sprintf( __( 'Edit “%s”' ), $att_title ) ),
  693.                     __( 'Edit' )
  694.                 );
  695.             }
  696.             if ( current_user_can( 'delete_post', $post->ID ) ) {
  697.                 if ( $this->is_trash ) {
  698.                     $actions['untrash'] = sprintf(
  699.                         '<a href="%s" class="submitdelete aria-button-if-js" aria-label="%s">%s</a>',
  700.                         wp_nonce_url( "post.php?action=untrash&post=$post->ID", 'untrash-post_' . $post->ID ),
  701.                         /* translators: %s: attachment title */
  702.                         esc_attr( sprintf( __( 'Restore “%s” from the Trash' ), $att_title ) ),
  703.                         __( 'Restore' )
  704.                     );
  705.                 } elseif ( EMPTY_TRASH_DAYS && MEDIA_TRASH ) {
  706.                     $actions['trash'] = sprintf(
  707.                         '<a href="%s" class="submitdelete aria-button-if-js" aria-label="%s">%s</a>',
  708.                         wp_nonce_url( "post.php?action=trash&post=$post->ID", 'trash-post_' . $post->ID ),
  709.                         /* translators: %s: attachment title */
  710.                         esc_attr( sprintf( __( 'Move “%s” to the Trash' ), $att_title ) ),
  711.                         _x( 'Trash', 'verb' )
  712.                     );
  713.                 }
  714.                 if ( $this->is_trash || ! EMPTY_TRASH_DAYS || ! MEDIA_TRASH ) {
  715.                     $delete_ays = ( !$this->is_trash && !MEDIA_TRASH ) ? " onclick='return showNotice.warn();'" : '';
  716.                     $actions['delete'] = sprintf(
  717.                         '<a href="%s" class="submitdelete aria-button-if-js"%s aria-label="%s">%s</a>',
  718.                         wp_nonce_url( "post.php?action=delete&post=$post->ID", 'delete-post_' . $post->ID ),
  719.                         $delete_ays,
  720.                         /* translators: %s: attachment title */
  721.                         esc_attr( sprintf( __( 'Delete “%s” permanently' ), $att_title ) ),
  722.                         __( 'Delete Permanently' )
  723.                     );
  724.                 }
  725.             }
  726.             if ( ! $this->is_trash ) {
  727.                 $actions['view'] = sprintf(
  728.                     '<a href="%s" aria-label="%s" rel="bookmark">%s</a>',
  729.                     get_permalink( $post->ID ),
  730.                     /* translators: %s: attachment title */
  731.                     esc_attr( sprintf( __( 'View “%s”' ), $att_title ) ),
  732.                     __( 'View' )
  733.                 );
  734.             }
  735.         }
  736.  
  737.         /**
  738.          * Filters the action links for each attachment in the Media list table.
  739.          *
  740.          * @since 2.8.0
  741.          *
  742.          * @param array   $actions  An array of action links for each attachment.
  743.          *                          Default 'Edit', 'Delete Permanently', 'View'.
  744.          * @param WP_Post $post     WP_Post object for the current attachment.
  745.          * @param bool    $detached Whether the list table contains media not attached
  746.          *                          to any posts. Default true.
  747.          */
  748.         return apply_filters( 'media_row_actions', $actions, $post, $this->detached );
  749.     }
  750.  
  751.     /**
  752.      * Generates and displays row action links.
  753.      *
  754.      * @since 4.3.0
  755.      *
  756.      * @param object $post        Attachment being acted upon.
  757.      * @param string $column_name Current column name.
  758.      * @param string $primary     Primary column name.
  759.      * @return string Row actions output for media attachments.
  760.      */
  761.     protected function handle_row_actions( $post, $column_name, $primary ) {
  762.         if ( $primary !== $column_name ) {
  763.             return '';
  764.         }
  765.  
  766.         $att_title = _draft_or_post_title();
  767.         return $this->row_actions( $this->_get_row_actions( $post, $att_title ) );
  768.     }
  769. }
  770.