Make WordPress Core

Ticket #38073: 38073.patch

File 38073.patch, 490.0 KB (added by davideferre, 8 years ago)
  • src/wp-admin/comment.php

    diff --git a/src/wp-admin/comment.php b/src/wp-admin/comment.php
    index c2eca11ec3..01081116b0 100644
    a b require_once( dirname( __FILE__ ) . '/admin.php' ); 
    1212$parent_file = 'edit-comments.php';
    1313$submenu_file = 'edit-comments.php';
    1414
    15 /**
    16  * @global string $action
    17  */
    18 global $action;
    19 wp_reset_vars( array('action') );
     15$action = wp_assign_request_var('action');
    2016
    2117if ( isset( $_POST['deletecomment'] ) )
    22         $action = 'deletecomment';
     18    $action = 'deletecomment';
    2319
    2420if ( 'cdc' == $action )
    25         $action = 'delete';
     21    $action = 'delete';
    2622elseif ( 'mac' == $action )
    27         $action = 'approve';
     23    $action = 'approve';
    2824
    2925if ( isset( $_GET['dt'] ) ) {
    30         if ( 'spam' == $_GET['dt'] )
    31                 $action = 'spam';
    32         elseif ( 'trash' == $_GET['dt'] )
    33                 $action = 'trash';
     26    if ( 'spam' == $_GET['dt'] )
     27        $action = 'spam';
     28    elseif ( 'trash' == $_GET['dt'] )
     29        $action = 'trash';
    3430}
    3531
    3632switch( $action ) {
    3733
    3834case 'editcomment' :
    39         $title = __('Edit Comment');
     35    $title = __('Edit Comment');
    4036
    41         get_current_screen()->add_help_tab( array(
    42                 'id'      => 'overview',
    43                 'title'   => __('Overview'),
    44                 'content' =>
    45                         '<p>' . __( 'You can edit the information left in a comment if needed. This is often useful when you notice that a commenter has made a typographical error.' ) . '</p>' .
    46                         '<p>' . __( 'You can also moderate the comment from this screen using the Status box, where you can also change the timestamp of the comment.' ) . '</p>'
    47         ) );
     37    get_current_screen()->add_help_tab( array(
     38        'id'      => 'overview',
     39        'title'   => __('Overview'),
     40        'content' =>
     41            '<p>' . __( 'You can edit the information left in a comment if needed. This is often useful when you notice that a commenter has made a typographical error.' ) . '</p>' .
     42            '<p>' . __( 'You can also moderate the comment from this screen using the Status box, where you can also change the timestamp of the comment.' ) . '</p>'
     43    ) );
    4844
    49         get_current_screen()->set_help_sidebar(
    50         '<p><strong>' . __( 'For more information:' ) . '</strong></p>' .
    51         '<p>' . __( '<a href="https://codex.wordpress.org/Administration_Screens#Comments">Documentation on Comments</a>' ) . '</p>' .
    52         '<p>' . __( '<a href="https://wordpress.org/support/">Support Forums</a>' ) . '</p>'
    53         );
     45    get_current_screen()->set_help_sidebar(
     46    '<p><strong>' . __( 'For more information:' ) . '</strong></p>' .
     47    '<p>' . __( '<a href="https://codex.wordpress.org/Administration_Screens#Comments">Documentation on Comments</a>' ) . '</p>' .
     48    '<p>' . __( '<a href="https://wordpress.org/support/">Support Forums</a>' ) . '</p>'
     49    );
    5450
    55         wp_enqueue_script('comment');
    56         require_once( ABSPATH . 'wp-admin/admin-header.php' );
     51    wp_enqueue_script('comment');
     52    require_once( ABSPATH . 'wp-admin/admin-header.php' );
    5753
    58         $comment_id = absint( $_GET['c'] );
     54    $comment_id = absint( $_GET['c'] );
    5955
    60         if ( !$comment = get_comment( $comment_id ) )
    61                 comment_footer_die( __( 'Invalid comment ID.' ) . sprintf(' <a href="%s">' . __('Go back') . '</a>.', 'javascript:history.go(-1)') );
     56    if ( !$comment = get_comment( $comment_id ) )
     57        comment_footer_die( __( 'Invalid comment ID.' ) . sprintf(' <a href="%s">' . __('Go back') . '</a>.', 'javascript:history.go(-1)') );
    6258
    63         if ( !current_user_can( 'edit_comment', $comment_id ) )
    64                 comment_footer_die( __('Sorry, you are not allowed to edit this comment.') );
     59    if ( !current_user_can( 'edit_comment', $comment_id ) )
     60        comment_footer_die( __('Sorry, you are not allowed to edit this comment.') );
    6561
    66         if ( 'trash' == $comment->comment_approved )
    67                 comment_footer_die( __('This comment is in the Trash. Please move it out of the Trash if you want to edit it.') );
     62    if ( 'trash' == $comment->comment_approved )
     63        comment_footer_die( __('This comment is in the Trash. Please move it out of the Trash if you want to edit it.') );
    6864
    69         $comment = get_comment_to_edit( $comment_id );
     65    $comment = get_comment_to_edit( $comment_id );
    7066
    71         include( ABSPATH . 'wp-admin/edit-form-comment.php' );
     67    include( ABSPATH . 'wp-admin/edit-form-comment.php' );
    7268
    73         break;
     69    break;
    7470
    7571case 'delete'  :
    7672case 'approve' :
    7773case 'trash'   :
    7874case 'spam'    :
    7975
    80         $title = __('Moderate Comment');
     76    $title = __('Moderate Comment');
    8177
    82         $comment_id = absint( $_GET['c'] );
     78    $comment_id = absint( $_GET['c'] );
    8379
    84         if ( ! $comment = get_comment( $comment_id ) ) {
    85                 wp_redirect( admin_url('edit-comments.php?error=1') );
    86                 die();
    87         }
     80    if ( ! $comment = get_comment( $comment_id ) ) {
     81        wp_redirect( admin_url('edit-comments.php?error=1') );
     82        die();
     83    }
    8884
    89         if ( !current_user_can( 'edit_comment', $comment->comment_ID ) ) {
    90                 wp_redirect( admin_url('edit-comments.php?error=2') );
    91                 die();
    92         }
     85    if ( !current_user_can( 'edit_comment', $comment->comment_ID ) ) {
     86        wp_redirect( admin_url('edit-comments.php?error=2') );
     87        die();
     88    }
    9389
    94         // No need to re-approve/re-trash/re-spam a comment.
    95         if ( $action == str_replace( '1', 'approve', $comment->comment_approved ) ) {
    96                 wp_redirect( admin_url( 'edit-comments.php?same=' . $comment_id ) );
    97                 die();
    98         }
     90    // No need to re-approve/re-trash/re-spam a comment.
     91    if ( $action == str_replace( '1', 'approve', $comment->comment_approved ) ) {
     92        wp_redirect( admin_url( 'edit-comments.php?same=' . $comment_id ) );
     93        die();
     94     }
    9995
    100         require_once( ABSPATH . 'wp-admin/admin-header.php' );
     96    require_once( ABSPATH . 'wp-admin/admin-header.php' );
    10197
    102         $formaction    = $action . 'comment';
    103         $nonce_action  = 'approve' == $action ? 'approve-comment_' : 'delete-comment_';
    104         $nonce_action .= $comment_id;
     98    $formaction    = $action . 'comment';
     99    $nonce_action  = 'approve' == $action ? 'approve-comment_' : 'delete-comment_';
     100    $nonce_action .= $comment_id;
    105101
    106102?>
    107103<div class="wrap">
    case 'spam' : 
    110106
    111107<?php
    112108switch ( $action ) {
    113         case 'spam' :
    114                 $caution_msg = __('You are about to mark the following comment as spam:');
    115                 $button      = _x( 'Mark as Spam', 'comment' );
    116                 break;
    117         case 'trash' :
    118                 $caution_msg = __('You are about to move the following comment to the Trash:');
    119                 $button      = __('Move to Trash');
    120                 break;
    121         case 'delete' :
    122                 $caution_msg = __('You are about to delete the following comment:');
    123                 $button      = __('Permanently Delete Comment');
    124                 break;
    125         default :
    126                 $caution_msg = __('You are about to approve the following comment:');
    127                 $button      = __('Approve Comment');
    128                 break;
     109    case 'spam' :
     110        $caution_msg = __('You are about to mark the following comment as spam:');
     111        $button      = _x( 'Mark as Spam', 'comment' );
     112        break;
     113    case 'trash' :
     114        $caution_msg = __('You are about to move the following comment to the Trash:');
     115        $button      = __('Move to Trash');
     116        break;
     117    case 'delete' :
     118        $caution_msg = __('You are about to delete the following comment:');
     119        $button      = __('Permanently Delete Comment');
     120        break;
     121    default :
     122        $caution_msg = __('You are about to approve the following comment:');
     123        $button      = __('Approve Comment');
     124        break;
    129125}
    130126
    131127if ( $comment->comment_approved != '0' ) { // if not unapproved
    132         $message = '';
    133         switch ( $comment->comment_approved ) {
    134                 case '1' :
    135                         $message = __('This comment is currently approved.');
    136                         break;
    137                 case 'spam' :
    138                         $message  = __('This comment is currently marked as spam.');
    139                         break;
    140                 case 'trash' :
    141                         $message  = __('This comment is currently in the Trash.');
    142                         break;
    143         }
    144         if ( $message ) {
    145                 echo '<div id="message" class="notice notice-info"><p>' . $message . '</p></div>';
    146         }
     128    $message = '';
     129    switch ( $comment->comment_approved ) {
     130        case '1' :
     131            $message = __('This comment is currently approved.');
     132            break;
     133        case 'spam' :
     134            $message  = __('This comment is currently marked as spam.');
     135            break;
     136        case 'trash' :
     137            $message  = __('This comment is currently in the Trash.');
     138            break;
     139    }
     140    if ( $message ) {
     141        echo '<div id="message" class="notice notice-info"><p>' . $message . '</p></div>';
     142    }
    147143}
    148144?>
    149145<div id="message" class="notice notice-warning"><p><strong><?php _e( 'Caution:' ); ?></strong> <?php echo $caution_msg; ?></p></div>
    if ( $comment->comment_approved != '0' ) { // if not unapproved 
    166162</tr>
    167163<?php } ?>
    168164<tr>
    169         <th scope="row"><?php /* translators: column name or table row header */ _e( 'In Response To' ); ?></th>
    170         <td>
    171         <?php
    172                 $post_id = $comment->comment_post_ID;
    173                 if ( current_user_can( 'edit_post', $post_id ) ) {
    174                         $post_link = "<a href='" . esc_url( get_edit_post_link( $post_id ) ) . "'>";
    175                         $post_link .= esc_html( get_the_title( $post_id ) ) . '</a>';
    176                 } else {
    177                         $post_link = esc_html( get_the_title( $post_id ) );
    178                 }
    179                 echo $post_link;
    180 
    181                 if ( $comment->comment_parent ) {
    182                         $parent      = get_comment( $comment->comment_parent );
    183                         $parent_link = esc_url( get_comment_link( $parent ) );
    184                         $name        = get_comment_author( $parent );
    185                         printf(
    186                                 /* translators: %s: comment link */
    187                                 ' | ' . __( 'In reply to %s.' ),
    188                                 '<a href="' . $parent_link . '">' . $name . '</a>'
    189                         );
    190                 }
    191         ?>
    192         </td>
     165    <th scope="row"><?php /* translators: column name or table row header */ _e( 'In Response To' ); ?></th>
     166    <td>
     167    <?php
     168        $post_id = $comment->comment_post_ID;
     169        if ( current_user_can( 'edit_post', $post_id ) ) {
     170            $post_link = "<a href='" . esc_url( get_edit_post_link( $post_id ) ) . "'>";
     171            $post_link .= esc_html( get_the_title( $post_id ) ) . '</a>';
     172        } else {
     173            $post_link = esc_html( get_the_title( $post_id ) );
     174        }
     175        echo $post_link;
     176
     177        if ( $comment->comment_parent ) {
     178            $parent      = get_comment( $comment->comment_parent );
     179            $parent_link = esc_url( get_comment_link( $parent ) );
     180            $name        = get_comment_author( $parent );
     181            printf(
     182                /* translators: %s: comment link */
     183                ' | ' . __( 'In reply to %s.' ),
     184                '<a href="' . $parent_link . '">' . $name . '</a>'
     185            );
     186        }
     187    ?>
     188    </td>
    193189</tr>
    194190<tr>
    195         <th scope="row"><?php _e( 'Submitted on' ); ?></th>
    196         <td>
    197         <?php
    198                 /* translators: 1: comment date, 2: comment time */
    199                 $submitted = sprintf( __( '%1$s at %2$s' ),
    200                         /* translators: comment date format. See https://secure.php.net/date */
    201                         get_comment_date( __( 'Y/m/d' ), $comment ),
    202                         get_comment_date( __( 'g:i a' ), $comment )
    203                 );
    204                 if ( 'approved' === wp_get_comment_status( $comment ) && ! empty ( $comment->comment_post_ID ) ) {
    205                         echo '<a href="' . esc_url( get_comment_link( $comment ) ) . '">' . $submitted . '</a>';
    206                 } else {
    207                         echo $submitted;
    208                 }
    209         ?>
    210         </td>
     191    <th scope="row"><?php _e( 'Submitted on' ); ?></th>
     192    <td>
     193    <?php
     194        /* translators: 1: comment date, 2: comment time */
     195        $submitted = sprintf( __( '%1$s at %2$s' ),
     196            /* translators: comment date format. See https://secure.php.net/date */
     197            get_comment_date( __( 'Y/m/d' ), $comment ),
     198            get_comment_date( __( 'g:i a' ), $comment )
     199        );
     200        if ( 'approved' === wp_get_comment_status( $comment ) && ! empty ( $comment->comment_post_ID ) ) {
     201            echo '<a href="' . esc_url( get_comment_link( $comment ) ) . '">' . $submitted . '</a>';
     202        } else {
     203            echo $submitted;
     204        }
     205    ?>
     206    </td>
    211207</tr>
    212208<tr>
    213209<th scope="row"><?php /* translators: field name in comment form */ _ex('Comment', 'noun'); ?></th>
    214210<td class="comment-content">
    215         <?php comment_text( $comment ); ?>
    216         <p class="edit-comment"><a href="<?php echo admin_url( "comment.php?action=editcomment&amp;c={$comment->comment_ID}" ); ?>"><?php esc_html_e( 'Edit' ); ?></a></p>
     211    <?php comment_text( $comment ); ?>
     212    <p class="edit-comment"><a href="<?php echo admin_url( "comment.php?action=editcomment&amp;c={$comment->comment_ID}" ); ?>"><?php esc_html_e( 'Edit' ); ?></a></p>
    217213</td>
    218214</tr>
    219215</table>
    if ( $comment->comment_approved != '0' ) { // if not unapproved 
    221217<form action="comment.php" method="get" class="comment-ays-submit">
    222218
    223219<p>
    224         <?php submit_button( $button, 'primary', 'submit', false ); ?>
    225         <a href="<?php echo admin_url('edit-comments.php'); ?>" class="button-cancel"><?php esc_html_e( 'Cancel' ); ?></a>
     220    <?php submit_button( $button, 'primary', 'submit', false ); ?>
     221    <a href="<?php echo admin_url('edit-comments.php'); ?>" class="button-cancel"><?php esc_html_e( 'Cancel' ); ?></a>
    226222</p>
    227223
    228224<?php wp_nonce_field( $nonce_action ); ?>
    if ( $comment->comment_approved != '0' ) { // if not unapproved 
    233229
    234230</div>
    235231<?php
    236         break;
     232    break;
    237233
    238234case 'deletecomment'    :
    239235case 'trashcomment'     :
    case 'spamcomment' : 
    242238case 'unspamcomment'    :
    243239case 'approvecomment'   :
    244240case 'unapprovecomment' :
    245         $comment_id = absint( $_REQUEST['c'] );
    246 
    247         if ( in_array( $action, array( 'approvecomment', 'unapprovecomment' ) ) )
    248                 check_admin_referer( 'approve-comment_' . $comment_id );
    249         else
    250                 check_admin_referer( 'delete-comment_' . $comment_id );
    251 
    252         $noredir = isset($_REQUEST['noredir']);
    253 
    254         if ( !$comment = get_comment($comment_id) )
    255                 comment_footer_die( __( 'Invalid comment ID.' ) . sprintf(' <a href="%s">' . __('Go back') . '</a>.', 'edit-comments.php') );
    256         if ( !current_user_can( 'edit_comment', $comment->comment_ID ) )
    257                 comment_footer_die( __('Sorry, you are not allowed to edit comments on this post.') );
    258 
    259         if ( '' != wp_get_referer() && ! $noredir && false === strpos(wp_get_referer(), 'comment.php') )
    260                 $redir = wp_get_referer();
    261         elseif ( '' != wp_get_original_referer() && ! $noredir )
    262                 $redir = wp_get_original_referer();
    263         elseif ( in_array( $action, array( 'approvecomment', 'unapprovecomment' ) ) )
    264                 $redir = admin_url('edit-comments.php?p=' . absint( $comment->comment_post_ID ) );
    265         else
    266                 $redir = admin_url('edit-comments.php');
    267 
    268         $redir = remove_query_arg( array('spammed', 'unspammed', 'trashed', 'untrashed', 'deleted', 'ids', 'approved', 'unapproved'), $redir );
    269 
    270         switch ( $action ) {
    271                 case 'deletecomment' :
    272                         wp_delete_comment( $comment );
    273                         $redir = add_query_arg( array('deleted' => '1'), $redir );
    274                         break;
    275                 case 'trashcomment' :
    276                         wp_trash_comment( $comment );
    277                         $redir = add_query_arg( array('trashed' => '1', 'ids' => $comment_id), $redir );
    278                         break;
    279                 case 'untrashcomment' :
    280                         wp_untrash_comment( $comment );
    281                         $redir = add_query_arg( array('untrashed' => '1'), $redir );
    282                         break;
    283                 case 'spamcomment' :
    284                         wp_spam_comment( $comment );
    285                         $redir = add_query_arg( array('spammed' => '1', 'ids' => $comment_id), $redir );
    286                         break;
    287                 case 'unspamcomment' :
    288                         wp_unspam_comment( $comment );
    289                         $redir = add_query_arg( array('unspammed' => '1'), $redir );
    290                         break;
    291                 case 'approvecomment' :
    292                         wp_set_comment_status( $comment, 'approve' );
    293                         $redir = add_query_arg( array( 'approved' => 1 ), $redir );
    294                         break;
    295                 case 'unapprovecomment' :
    296                         wp_set_comment_status( $comment, 'hold' );
    297                         $redir = add_query_arg( array( 'unapproved' => 1 ), $redir );
    298                         break;
    299         }
    300 
    301         wp_redirect( $redir );
    302         die;
     241    $comment_id = absint( $_REQUEST['c'] );
     242
     243    if ( in_array( $action, array( 'approvecomment', 'unapprovecomment' ) ) )
     244        check_admin_referer( 'approve-comment_' . $comment_id );
     245    else
     246        check_admin_referer( 'delete-comment_' . $comment_id );
     247
     248    $noredir = isset($_REQUEST['noredir']);
     249
     250    if ( !$comment = get_comment($comment_id) )
     251        comment_footer_die( __( 'Invalid comment ID.' ) . sprintf(' <a href="%s">' . __('Go back') . '</a>.', 'edit-comments.php') );
     252    if ( !current_user_can( 'edit_comment', $comment->comment_ID ) )
     253        comment_footer_die( __('Sorry, you are not allowed to edit comments on this post.') );
     254
     255    if ( '' != wp_get_referer() && ! $noredir && false === strpos(wp_get_referer(), 'comment.php') )
     256        $redir = wp_get_referer();
     257    elseif ( '' != wp_get_original_referer() && ! $noredir )
     258        $redir = wp_get_original_referer();
     259    elseif ( in_array( $action, array( 'approvecomment', 'unapprovecomment' ) ) )
     260        $redir = admin_url('edit-comments.php?p=' . absint( $comment->comment_post_ID ) );
     261    else
     262        $redir = admin_url('edit-comments.php');
     263
     264    $redir = remove_query_arg( array('spammed', 'unspammed', 'trashed', 'untrashed', 'deleted', 'ids', 'approved', 'unapproved'), $redir );
     265
     266    switch ( $action ) {
     267        case 'deletecomment' :
     268            wp_delete_comment( $comment );
     269            $redir = add_query_arg( array('deleted' => '1'), $redir );
     270            break;
     271        case 'trashcomment' :
     272            wp_trash_comment( $comment );
     273            $redir = add_query_arg( array('trashed' => '1', 'ids' => $comment_id), $redir );
     274            break;
     275        case 'untrashcomment' :
     276            wp_untrash_comment( $comment );
     277            $redir = add_query_arg( array('untrashed' => '1'), $redir );
     278            break;
     279        case 'spamcomment' :
     280            wp_spam_comment( $comment );
     281            $redir = add_query_arg( array('spammed' => '1', 'ids' => $comment_id), $redir );
     282            break;
     283        case 'unspamcomment' :
     284            wp_unspam_comment( $comment );
     285            $redir = add_query_arg( array('unspammed' => '1'), $redir );
     286            break;
     287        case 'approvecomment' :
     288            wp_set_comment_status( $comment, 'approve' );
     289            $redir = add_query_arg( array( 'approved' => 1 ), $redir );
     290            break;
     291        case 'unapprovecomment' :
     292            wp_set_comment_status( $comment, 'hold' );
     293            $redir = add_query_arg( array( 'unapproved' => 1 ), $redir );
     294            break;
     295    }
     296
     297    wp_redirect( $redir );
     298    die;
    303299
    304300case 'editedcomment' :
    305301
    306         $comment_id = absint( $_POST['comment_ID'] );
    307         $comment_post_id = absint( $_POST['comment_post_ID'] );
     302    $comment_id = absint( $_POST['comment_ID'] );
     303    $comment_post_id = absint( $_POST['comment_post_ID'] );
    308304
    309         check_admin_referer( 'update-comment_' . $comment_id );
     305    check_admin_referer( 'update-comment_' . $comment_id );
    310306
    311         edit_comment();
     307    edit_comment();
    312308
    313         $location = ( empty( $_POST['referredby'] ) ? "edit-comments.php?p=$comment_post_id" : $_POST['referredby'] ) . '#comment-' . $comment_id;
     309    $location = ( empty( $_POST['referredby'] ) ? "edit-comments.php?p=$comment_post_id" : $_POST['referredby'] ) . '#comment-' . $comment_id;
    314310
    315         /**
    316         * Filters the URI the user is redirected to after editing a comment in the admin.
    317         *
    318         * @since 2.1.0
    319         *
    320         * @param string $location The URI the user will be redirected to.
    321         * @param int $comment_id The ID of the comment being edited.
    322         */
    323         $location = apply_filters( 'comment_edit_redirect', $location, $comment_id );
    324         wp_redirect( $location );
     311    /**
     312    * Filters the URI the user is redirected to after editing a comment in the admin.
     313    *
     314    * @since 2.1.0
     315    *
     316    * @param string $location The URI the user will be redirected to.
     317    * @param int $comment_id The ID of the comment being edited.
     318    */
     319    $location = apply_filters( 'comment_edit_redirect', $location, $comment_id );
     320    wp_redirect( $location );
    325321
    326         exit();
     322    exit();
    327323
    328324default:
    329         wp_die( __('Unknown action.') );
     325    wp_die( __('Unknown action.') );
    330326
    331327} // end switch
    332328
  • src/wp-admin/customize.php

    diff --git a/src/wp-admin/customize.php b/src/wp-admin/customize.php
    index f1bf8aa9a1..2401ada6d0 100644
    a b define( 'IFRAME_REQUEST', true ); 
    1313require_once( dirname( __FILE__ ) . '/admin.php' );
    1414
    1515if ( ! current_user_can( 'customize' ) ) {
    16         wp_die(
    17                 '<h1>' . __( 'Cheatin&#8217; uh?' ) . '</h1>' .
    18                 '<p>' . __( 'Sorry, you are not allowed to customize this site.' ) . '</p>',
    19                 403
    20         );
     16    wp_die(
     17        '<h1>' . __( 'Cheatin&#8217; uh?' ) . '</h1>' .
     18        '<p>' . __( 'Sorry, you are not allowed to customize this site.' ) . '</p>',
     19        403
     20    );
    2121}
    2222
    2323/**
    if ( ! current_user_can( 'customize' ) ) { 
    2727global $wp_scripts, $wp_customize;
    2828
    2929if ( $wp_customize->changeset_post_id() ) {
    30         if ( ! current_user_can( get_post_type_object( 'customize_changeset' )->cap->edit_post, $wp_customize->changeset_post_id() ) ) {
    31                 wp_die(
    32                         '<h1>' . __( 'Cheatin&#8217; uh?' ) . '</h1>' .
    33                         '<p>' . __( 'Sorry, you are not allowed to edit this changeset.' ) . '</p>',
    34                         403
    35                 );
    36         }
    37         if ( in_array( get_post_status( $wp_customize->changeset_post_id() ), array( 'publish', 'trash' ), true ) ) {
    38                 wp_die(
    39                         '<h1>' . __( 'Cheatin&#8217; uh?' ) . '</h1>' .
    40                         '<p>' . __( 'This changeset has already been published and cannot be further modified.' ) . '</p>' .
    41                         '<p><a href="' . esc_url( remove_query_arg( 'changeset_uuid' ) ) . '">' . __( 'Customize New Changes' ) . '</a></p>',
    42                         403
    43                 );
    44         }
     30    if ( ! current_user_can( get_post_type_object( 'customize_changeset' )->cap->edit_post, $wp_customize->changeset_post_id() ) ) {
     31        wp_die(
     32            '<h1>' . __( 'Cheatin&#8217; uh?' ) . '</h1>' .
     33            '<p>' . __( 'Sorry, you are not allowed to edit this changeset.' ) . '</p>',
     34            403
     35        );
     36    }
     37    if ( in_array( get_post_status( $wp_customize->changeset_post_id() ), array( 'publish', 'trash' ), true ) ) {
     38        wp_die(
     39            '<h1>' . __( 'Cheatin&#8217; uh?' ) . '</h1>' .
     40            '<p>' . __( 'This changeset has already been published and cannot be further modified.' ) . '</p>' .
     41            '<p><a href="' . esc_url( remove_query_arg( 'changeset_uuid' ) ) . '">' . __( 'Customize New Changes' ) . '</a></p>',
     42            403
     43        );
     44    }
    4545}
    4646
    47 
    48 wp_reset_vars( array( 'url', 'return', 'autofocus' ) );
     47$url = wp_assign_request_var('url');
    4948if ( ! empty( $url ) ) {
    50         $wp_customize->set_preview_url( wp_unslash( $url ) );
     49    $wp_customize->set_preview_url( wp_unslash( $url ) );
    5150}
     51
     52$return = wp_assign_request_var('return');
    5253if ( ! empty( $return ) ) {
    53         $wp_customize->set_return_url( wp_unslash( $return ) );
     54    $wp_customize->set_return_url( wp_unslash( $return ) );
    5455}
     56
     57$autofocus = wp_assign_request_var('autofocus');
    5558if ( ! empty( $autofocus ) && is_array( $autofocus ) ) {
    56         $wp_customize->set_autofocus( wp_unslash( $autofocus ) );
     59    $wp_customize->set_autofocus( wp_unslash( $autofocus ) );
    5760}
    5861
    5962$registered = $wp_scripts->registered;
    _wp_admin_html_begin(); 
    9093$body_class = 'wp-core-ui wp-customizer js';
    9194
    9295if ( wp_is_mobile() ) :
    93         $body_class .= ' mobile';
     96    $body_class .= ' mobile';
    9497
    95         ?><meta name="viewport" id="viewport-meta" content="width=device-width, initial-scale=1.0, minimum-scale=0.5, maximum-scale=1.2" /><?php
     98    ?><meta name="viewport" id="viewport-meta" content="width=device-width, initial-scale=1.0, minimum-scale=0.5, maximum-scale=1.2" /><?php
    9699endif;
    97100
    98101if ( $wp_customize->is_ios() ) {
    99         $body_class .= ' ios';
     102    $body_class .= ' ios';
    100103}
    101104
    102105if ( is_rtl() ) {
    103         $body_class .= ' rtl';
     106    $body_class .= ' rtl';
    104107}
    105108$body_class .= ' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_user_locale() ) ) );
    106109
    do_action( 'customize_controls_print_scripts' ); 
    130133</head>
    131134<body class="<?php echo esc_attr( $body_class ); ?>">
    132135<div class="wp-full-overlay expanded">
    133         <form id="customize-controls" class="wrap wp-full-overlay-sidebar">
    134                 <div id="customize-header-actions" class="wp-full-overlay-header">
    135                         <?php
    136                         $save_text = $wp_customize->is_theme_active() ? __( 'Save &amp; Publish' ) : __( 'Save &amp; Activate' );
    137                         $save_attrs = array();
    138                         if ( ! current_user_can( get_post_type_object( 'customize_changeset' )->cap->publish_posts ) ) {
    139                                 $save_attrs['style'] = 'display: none';
    140                         }
    141                         submit_button( $save_text, 'primary save', 'save', false, $save_attrs );
    142                         ?>
    143                         <span class="spinner"></span>
    144                         <button type="button" class="customize-controls-preview-toggle">
    145                                 <span class="controls"><?php _e( 'Customize' ); ?></span>
    146                                 <span class="preview"><?php _e( 'Preview' ); ?></span>
    147                         </button>
    148                         <a class="customize-controls-close" href="<?php echo esc_url( $wp_customize->get_return_url() ); ?>">
    149                                 <span class="screen-reader-text"><?php _e( 'Close the Customizer and go back to the previous page' ); ?></span>
    150                         </a>
    151                 </div>
    152 
    153                 <div id="widgets-right" class="wp-clearfix"><!-- For Widget Customizer, many widgets try to look for instances under div#widgets-right, so we have to add that ID to a container div in the Customizer for compat -->
    154                 <div class="wp-full-overlay-sidebar-content" tabindex="-1">
    155                         <div id="customize-info" class="accordion-section customize-info">
    156                                 <div class="accordion-section-title">
    157                                         <span class="preview-notice"><?php
    158                                                 echo sprintf( __( 'You are customizing %s' ), '<strong class="panel-title site-title">' . get_bloginfo( 'name', 'display' ) . '</strong>' );
    159                                         ?></span>
    160                                         <button type="button" class="customize-help-toggle dashicons dashicons-editor-help" aria-expanded="false"><span class="screen-reader-text"><?php _e( 'Help' ); ?></span></button>
    161                                 </div>
    162                                 <div class="customize-panel-description"><?php
    163                                         _e( 'The Customizer allows you to preview changes to your site before publishing them. You can navigate to different pages on your site within the preview. Edit shortcuts are shown for some editable elements.' );
    164                                 ?></div>
    165                         </div>
    166 
    167                         <div id="customize-theme-controls">
    168                                 <ul class="customize-pane-parent"><?php // Panels and sections are managed here via JavaScript ?></ul>
    169                         </div>
    170                 </div>
    171                 </div>
    172 
    173                 <div id="customize-footer-actions" class="wp-full-overlay-footer">
    174                         <button type="button" class="collapse-sidebar button" aria-expanded="true" aria-label="<?php echo esc_attr( _x( 'Hide Controls', 'label for hide controls button without length constraints' ) ); ?>">
    175                                 <span class="collapse-sidebar-arrow"></span>
    176                                 <span class="collapse-sidebar-label"><?php _ex( 'Hide Controls', 'short (~12 characters) label for hide controls button' ); ?></span>
    177                         </button>
    178                         <?php $previewable_devices = $wp_customize->get_previewable_devices(); ?>
    179                         <?php if ( ! empty( $previewable_devices ) ) : ?>
    180                         <div class="devices-wrapper">
    181                                 <div class="devices">
    182                                         <?php foreach ( (array) $previewable_devices as $device => $settings ) : ?>
    183                                                 <?php
    184                                                 if ( empty( $settings['label'] ) ) {
    185                                                         continue;
    186                                                 }
    187                                                 $active = ! empty( $settings['default'] );
    188                                                 $class = 'preview-' . $device;
    189                                                 if ( $active ) {
    190                                                         $class .= ' active';
    191                                                 }
    192                                                 ?>
    193                                                 <button type="button" class="<?php echo esc_attr( $class ); ?>" aria-pressed="<?php echo esc_attr( $active ) ?>" data-device="<?php echo esc_attr( $device ); ?>">
    194                                                         <span class="screen-reader-text"><?php echo esc_html( $settings['label'] ); ?></span>
    195                                                 </button>
    196                                         <?php endforeach; ?>
    197                                 </div>
    198                         </div>
    199                         <?php endif; ?>
    200                 </div>
    201         </form>
    202         <div id="customize-preview" class="wp-full-overlay-main"></div>
    203         <?php
    204 
    205         /**
    206         * Prints templates, control scripts, and settings in the footer.
    207         *
    208         * @since 3.4.0
    209         */
    210         do_action( 'customize_controls_print_footer_scripts' );
    211         ?>
     136    <form id="customize-controls" class="wrap wp-full-overlay-sidebar">
     137        <div id="customize-header-actions" class="wp-full-overlay-header">
     138            <?php
     139            $save_text = $wp_customize->is_theme_active() ? __( 'Save &amp; Publish' ) : __( 'Save &amp; Activate' );
     140            $save_attrs = array();
     141            if ( ! current_user_can( get_post_type_object( 'customize_changeset' )->cap->publish_posts ) ) {
     142                $save_attrs['style'] = 'display: none';
     143            }
     144            submit_button( $save_text, 'primary save', 'save', false, $save_attrs );
     145            ?>
     146            <span class="spinner"></span>
     147            <button type="button" class="customize-controls-preview-toggle">
     148                <span class="controls"><?php _e( 'Customize' ); ?></span>
     149                <span class="preview"><?php _e( 'Preview' ); ?></span>
     150            </button>
     151            <a class="customize-controls-close" href="<?php echo esc_url( $wp_customize->get_return_url() ); ?>">
     152                <span class="screen-reader-text"><?php _e( 'Close the Customizer and go back to the previous page' ); ?></span>
     153            </a>
     154        </div>
     155
     156        <div id="widgets-right" class="wp-clearfix"><!-- For Widget Customizer, many widgets try to look for instances under div#widgets-right, so we have to add that ID to a container div in the Customizer for compat -->
     157        <div class="wp-full-overlay-sidebar-content" tabindex="-1">
     158            <div id="customize-info" class="accordion-section customize-info">
     159                <div class="accordion-section-title">
     160                    <span class="preview-notice"><?php
     161                        echo sprintf( __( 'You are customizing %s' ), '<strong class="panel-title site-title">' . get_bloginfo( 'name', 'display' ) . '</strong>' );
     162                    ?></span>
     163                    <button type="button" class="customize-help-toggle dashicons dashicons-editor-help" aria-expanded="false"><span class="screen-reader-text"><?php _e( 'Help' ); ?></span></button>
     164                </div>
     165                <div class="customize-panel-description"><?php
     166                    _e( 'The Customizer allows you to preview changes to your site before publishing them. You can navigate to different pages on your site within the preview. Edit shortcuts are shown for some editable elements.' );
     167                ?></div>
     168            </div>
     169
     170            <div id="customize-theme-controls">
     171                <ul class="customize-pane-parent"><?php // Panels and sections are managed here via JavaScript ?></ul>
     172            </div>
     173        </div>
     174        </div>
     175
     176        <div id="customize-footer-actions" class="wp-full-overlay-footer">
     177            <button type="button" class="collapse-sidebar button" aria-expanded="true" aria-label="<?php echo esc_attr( _x( 'Hide Controls', 'label for hide controls button without length constraints' ) ); ?>">
     178                <span class="collapse-sidebar-arrow"></span>
     179                <span class="collapse-sidebar-label"><?php _ex( 'Hide Controls', 'short (~12 characters) label for hide controls button' ); ?></span>
     180            </button>
     181            <?php $previewable_devices = $wp_customize->get_previewable_devices(); ?>
     182            <?php if ( ! empty( $previewable_devices ) ) : ?>
     183            <div class="devices-wrapper">
     184                <div class="devices">
     185                    <?php foreach ( (array) $previewable_devices as $device => $settings ) : ?>
     186                        <?php
     187                        if ( empty( $settings['label'] ) ) {
     188                            continue;
     189                        }
     190                        $active = ! empty( $settings['default'] );
     191                        $class = 'preview-' . $device;
     192                        if ( $active ) {
     193                            $class .= ' active';
     194                        }
     195                        ?>
     196                        <button type="button" class="<?php echo esc_attr( $class ); ?>" aria-pressed="<?php echo esc_attr( $active ) ?>" data-device="<?php echo esc_attr( $device ); ?>">
     197                            <span class="screen-reader-text"><?php echo esc_html( $settings['label'] ); ?></span>
     198                        </button>
     199                    <?php endforeach; ?>
     200                </div>
     201            </div>
     202            <?php endif; ?>
     203        </div>
     204    </form>
     205    <div id="customize-preview" class="wp-full-overlay-main"></div>
     206    <?php
     207
     208    /**
     209    * Prints templates, control scripts, and settings in the footer.
     210    *
     211    * @since 3.4.0
     212    */
     213    do_action( 'customize_controls_print_footer_scripts' );
     214    ?>
    212215</div>
    213216</body>
    214217</html>
  • src/wp-admin/edit-tag-form.php

    diff --git a/src/wp-admin/edit-tag-form.php b/src/wp-admin/edit-tag-form.php
    index e3fb222bc9..3108186446 100644
    a b  
    88
    99// don't load directly
    1010if ( ! defined( 'ABSPATH' ) ) {
    11         die( '-1' );
     11    die( '-1' );
    1212}
    1313
    1414// Back compat hooks
    1515if ( 'category' == $taxonomy ) {
    16         /**
    17          * Fires before the Edit Category form.
    18         *
    19         * @since 2.1.0
    20         * @deprecated 3.0.0 Use {$taxonomy}_pre_edit_form instead.
    21         *
    22         * @param object $tag Current category term object.
    23         */
    24         do_action( 'edit_category_form_pre', $tag );
     16    /**
     17     * Fires before the Edit Category form.
     18    *
     19    * @since 2.1.0
     20    * @deprecated 3.0.0 Use {$taxonomy}_pre_edit_form instead.
     21    *
     22    * @param object $tag Current category term object.
     23    */
     24    do_action( 'edit_category_form_pre', $tag );
    2525} elseif ( 'link_category' == $taxonomy ) {
    26         /**
    27         * Fires before the Edit Link Category form.
    28         *
    29         * @since 2.3.0
    30         * @deprecated 3.0.0 Use {$taxonomy}_pre_edit_form instead.
    31         *
    32         * @param object $tag Current link category term object.
    33         */
    34         do_action( 'edit_link_category_form_pre', $tag );
     26    /**
     27    * Fires before the Edit Link Category form.
     28    *
     29    * @since 2.3.0
     30    * @deprecated 3.0.0 Use {$taxonomy}_pre_edit_form instead.
     31    *
     32    * @param object $tag Current link category term object.
     33    */
     34    do_action( 'edit_link_category_form_pre', $tag );
    3535} else {
    36         /**
    37         * Fires before the Edit Tag form.
    38         *
    39         * @since 2.5.0
    40         * @deprecated 3.0.0 Use {$taxonomy}_pre_edit_form instead.
    41         *
    42         * @param object $tag Current tag term object.
    43         */
    44         do_action( 'edit_tag_form_pre', $tag );
     36    /**
     37    * Fires before the Edit Tag form.
     38    *
     39    * @since 2.5.0
     40    * @deprecated 3.0.0 Use {$taxonomy}_pre_edit_form instead.
     41    *
     42    * @param object $tag Current tag term object.
     43    */
     44    do_action( 'edit_tag_form_pre', $tag );
    4545}
    4646
    47 /**
    48  * Use with caution, see https://codex.wordpress.org/Function_Reference/wp_reset_vars
    49  */
    50 wp_reset_vars( array( 'wp_http_referer' ) );
     47$wp_http_referer = wp_assign_request_var('$wp_http_referer');
    5148
    5249$wp_http_referer = remove_query_arg( array( 'action', 'message', 'tag_ID' ), $wp_http_referer );
    5350
    do_action( "{$taxonomy}_pre_edit_form", $tag, $taxonomy ); ?> 
    7269
    7370<?php if ( $message ) : ?>
    7471<div id="message" class="updated">
    75         <p><strong><?php echo $message; ?></strong></p>
    76         <?php if ( $wp_http_referer ) { ?>
    77         <p><a href="<?php echo esc_url( $wp_http_referer ); ?>"><?php
    78                 /* translators: %s: taxonomy name */
    79                 printf( _x( '&larr; Back to %s', 'admin screen' ), $tax->labels->name );
    80         ?></a></p>
    81         <?php } ?>
     72    <p><strong><?php echo $message; ?></strong></p>
     73    <?php if ( $wp_http_referer ) { ?>
     74    <p><a href="<?php echo esc_url( $wp_http_referer ); ?>"><?php
     75        /* translators: %s: taxonomy name */
     76        printf( _x( '&larr; Back to %s', 'admin screen' ), $tax->labels->name );
     77    ?></a></p>
     78    <?php } ?>
    8279</div>
    8380<?php endif; ?>
    8481
    wp_nonce_field( 'update-tag_' . $tag_ID ); 
    115112 */
    116113do_action( "{$taxonomy}_term_edit_form_top", $tag, $taxonomy );
    117114?>
    118         <table class="form-table">
    119                 <tr class="form-field form-required term-name-wrap">
    120                         <th scope="row"><label for="name"><?php _ex( 'Name', 'term name' ); ?></label></th>
    121                         <td><input name="name" id="name" type="text" value="<?php if ( isset( $tag->name ) ) echo esc_attr($tag->name); ?>" size="40" aria-required="true" />
    122                         <p class="description"><?php _e('The name is how it appears on your site.'); ?></p></td>
    123                 </tr>
     115    <table class="form-table">
     116        <tr class="form-field form-required term-name-wrap">
     117            <th scope="row"><label for="name"><?php _ex( 'Name', 'term name' ); ?></label></th>
     118            <td><input name="name" id="name" type="text" value="<?php if ( isset( $tag->name ) ) echo esc_attr($tag->name); ?>" size="40" aria-required="true" />
     119            <p class="description"><?php _e('The name is how it appears on your site.'); ?></p></td>
     120        </tr>
    124121<?php if ( !global_terms_enabled() ) { ?>
    125                 <tr class="form-field term-slug-wrap">
    126                         <th scope="row"><label for="slug"><?php _e( 'Slug' ); ?></label></th>
    127                         <?php
    128                         /**
    129                         * Filters the editable slug.
    130                         *
    131                         * Note: This is a multi-use hook in that it is leveraged both for editable
    132                         * post URIs and term slugs.
    133                         *
    134                         * @since 2.6.0
    135                         * @since 4.4.0 The `$tag` parameter was added.
    136                         *
    137                         * @param string         $slug The editable slug. Will be either a term slug or post URI depending
    138                         *                             upon the context in which it is evaluated.
    139                         * @param object|WP_Post $tag  Term or WP_Post object.
    140                         */
    141                         $slug = isset( $tag->slug ) ? apply_filters( 'editable_slug', $tag->slug, $tag ) : '';
    142                         ?>
    143                         <td><input name="slug" id="slug" type="text" value="<?php echo esc_attr( $slug ); ?>" size="40" />
    144                         <p class="description"><?php _e('The &#8220;slug&#8221; is the URL-friendly version of the name. It is usually all lowercase and contains only letters, numbers, and hyphens.'); ?></p></td>
    145                 </tr>
     122        <tr class="form-field term-slug-wrap">
     123            <th scope="row"><label for="slug"><?php _e( 'Slug' ); ?></label></th>
     124            <?php
     125            /**
     126            * Filters the editable slug.
     127            *
     128            * Note: This is a multi-use hook in that it is leveraged both for editable
     129            * post URIs and term slugs.
     130            *
     131            * @since 2.6.0
     132            * @since 4.4.0 The `$tag` parameter was added.
     133            *
     134            * @param string         $slug The editable slug. Will be either a term slug or post URI depending
     135            *                             upon the context in which it is evaluated.
     136            * @param object|WP_Post $tag  Term or WP_Post object.
     137            */
     138            $slug = isset( $tag->slug ) ? apply_filters( 'editable_slug', $tag->slug, $tag ) : '';
     139            ?>
     140            <td><input name="slug" id="slug" type="text" value="<?php echo esc_attr( $slug ); ?>" size="40" />
     141            <p class="description"><?php _e('The &#8220;slug&#8221; is the URL-friendly version of the name. It is usually all lowercase and contains only letters, numbers, and hyphens.'); ?></p></td>
     142        </tr>
    146143<?php } ?>
    147144<?php if ( is_taxonomy_hierarchical($taxonomy) ) : ?>
    148                 <tr class="form-field term-parent-wrap">
    149                         <th scope="row"><label for="parent"><?php echo esc_html( $tax->labels->parent_item ); ?></label></th>
    150                         <td>
    151                                 <?php
    152                                 $dropdown_args = array(
    153                                         'hide_empty'       => 0,
    154                                         'hide_if_empty'    => false,
    155                                         'taxonomy'         => $taxonomy,
    156                                         'name'             => 'parent',
    157                                         'orderby'          => 'name',
    158                                         'selected'         => $tag->parent,
    159                                         'exclude_tree'     => $tag->term_id,
    160                                         'hierarchical'     => true,
    161                                         'show_option_none' => __( 'None' ),
    162                                 );
     145        <tr class="form-field term-parent-wrap">
     146            <th scope="row"><label for="parent"><?php echo esc_html( $tax->labels->parent_item ); ?></label></th>
     147            <td>
     148                <?php
     149                $dropdown_args = array(
     150                    'hide_empty'       => 0,
     151                    'hide_if_empty'    => false,
     152                    'taxonomy'         => $taxonomy,
     153                    'name'             => 'parent',
     154                    'orderby'          => 'name',
     155                    'selected'         => $tag->parent,
     156                    'exclude_tree'     => $tag->term_id,
     157                    'hierarchical'     => true,
     158                    'show_option_none' => __( 'None' ),
     159                );
    163160
    164                                 /** This filter is documented in wp-admin/edit-tags.php */
    165                                 $dropdown_args = apply_filters( 'taxonomy_parent_dropdown_args', $dropdown_args, $taxonomy, 'edit' );
    166                                 wp_dropdown_categories( $dropdown_args ); ?>
    167                                 <?php if ( 'category' == $taxonomy ) : ?>
    168                                         <p class="description"><?php _e( 'Categories, unlike tags, can have a hierarchy. You might have a Jazz category, and under that have children categories for Bebop and Big Band. Totally optional.' ); ?></p>
    169                                 <?php else : ?>
    170                                         <p class="description"><?php _e( 'Assign a parent term to create a hierarchy. The term Jazz, for example, would be the parent of Bebop and Big Band.' ); ?></p>
    171                                 <?php endif; ?>
    172                         </td>
    173                 </tr>
     161                /** This filter is documented in wp-admin/edit-tags.php */
     162                $dropdown_args = apply_filters( 'taxonomy_parent_dropdown_args', $dropdown_args, $taxonomy, 'edit' );
     163                wp_dropdown_categories( $dropdown_args ); ?>
     164                <?php if ( 'category' == $taxonomy ) : ?>
     165                    <p class="description"><?php _e( 'Categories, unlike tags, can have a hierarchy. You might have a Jazz category, and under that have children categories for Bebop and Big Band. Totally optional.' ); ?></p>
     166                <?php else : ?>
     167                    <p class="description"><?php _e( 'Assign a parent term to create a hierarchy. The term Jazz, for example, would be the parent of Bebop and Big Band.' ); ?></p>
     168                <?php endif; ?>
     169            </td>
     170        </tr>
    174171<?php endif; // is_taxonomy_hierarchical() ?>
    175                 <tr class="form-field term-description-wrap">
    176                         <th scope="row"><label for="description"><?php _e( 'Description' ); ?></label></th>
    177                         <td><textarea name="description" id="description" rows="5" cols="50" class="large-text"><?php echo $tag->description; // textarea_escaped ?></textarea>
    178                         <p class="description"><?php _e('The description is not prominent by default; however, some themes may show it.'); ?></p></td>
    179                 </tr>
    180                 <?php
    181                 // Back compat hooks
    182                 if ( 'category' == $taxonomy ) {
    183                         /**
    184                         * Fires after the Edit Category form fields are displayed.
    185                         *
    186                         * @since 2.9.0
    187                         * @deprecated 3.0.0 Use {$taxonomy}_edit_form_fields instead.
    188                         *
    189                         * @param object $tag Current category term object.
    190                         */
    191                         do_action( 'edit_category_form_fields', $tag );
    192                 } elseif ( 'link_category' == $taxonomy ) {
    193                         /**
    194                         * Fires after the Edit Link Category form fields are displayed.
    195                         *
    196                         * @since 2.9.0
    197                         * @deprecated 3.0.0 Use {$taxonomy}_edit_form_fields instead.
    198                         *
    199                         * @param object $tag Current link category term object.
    200                         */
    201                         do_action( 'edit_link_category_form_fields', $tag );
    202                 } else {
    203                         /**
    204                         * Fires after the Edit Tag form fields are displayed.
    205                         *
    206                         * @since 2.9.0
    207                         * @deprecated 3.0.0 Use {$taxonomy}_edit_form_fields instead.
    208                         *
    209                         * @param object $tag Current tag term object.
    210                         */
    211                         do_action( 'edit_tag_form_fields', $tag );
    212                 }
    213                 /**
    214                 * Fires after the Edit Term form fields are displayed.
    215                 *
    216                 * The dynamic portion of the hook name, `$taxonomy`, refers to
    217                 * the taxonomy slug.
    218                 *
    219                 * @since 3.0.0
    220                 *
    221                 * @param object $tag      Current taxonomy term object.
    222                 * @param string $taxonomy Current taxonomy slug.
    223                 */
    224                 do_action( "{$taxonomy}_edit_form_fields", $tag, $taxonomy );
    225                 ?>
    226         </table>
     172        <tr class="form-field term-description-wrap">
     173            <th scope="row"><label for="description"><?php _e( 'Description' ); ?></label></th>
     174            <td><textarea name="description" id="description" rows="5" cols="50" class="large-text"><?php echo $tag->description; // textarea_escaped ?></textarea>
     175            <p class="description"><?php _e('The description is not prominent by default; however, some themes may show it.'); ?></p></td>
     176        </tr>
     177        <?php
     178        // Back compat hooks
     179        if ( 'category' == $taxonomy ) {
     180            /**
     181            * Fires after the Edit Category form fields are displayed.
     182            *
     183            * @since 2.9.0
     184            * @deprecated 3.0.0 Use {$taxonomy}_edit_form_fields instead.
     185            *
     186            * @param object $tag Current category term object.
     187            */
     188            do_action( 'edit_category_form_fields', $tag );
     189        } elseif ( 'link_category' == $taxonomy ) {
     190            /**
     191            * Fires after the Edit Link Category form fields are displayed.
     192            *
     193            * @since 2.9.0
     194            * @deprecated 3.0.0 Use {$taxonomy}_edit_form_fields instead.
     195            *
     196            * @param object $tag Current link category term object.
     197            */
     198            do_action( 'edit_link_category_form_fields', $tag );
     199        } else {
     200            /**
     201            * Fires after the Edit Tag form fields are displayed.
     202            *
     203            * @since 2.9.0
     204            * @deprecated 3.0.0 Use {$taxonomy}_edit_form_fields instead.
     205            *
     206            * @param object $tag Current tag term object.
     207            */
     208            do_action( 'edit_tag_form_fields', $tag );
     209        }
     210        /**
     211        * Fires after the Edit Term form fields are displayed.
     212        *
     213        * The dynamic portion of the hook name, `$taxonomy`, refers to
     214        * the taxonomy slug.
     215        *
     216        * @since 3.0.0
     217        *
     218        * @param object $tag      Current taxonomy term object.
     219        * @param string $taxonomy Current taxonomy slug.
     220        */
     221        do_action( "{$taxonomy}_edit_form_fields", $tag, $taxonomy );
     222        ?>
     223    </table>
    227224<?php
    228225// Back compat hooks
    229226if ( 'category' == $taxonomy ) {
    230         /** This action is documented in wp-admin/edit-tags.php */
    231         do_action( 'edit_category_form', $tag );
     227    /** This action is documented in wp-admin/edit-tags.php */
     228    do_action( 'edit_category_form', $tag );
    232229} elseif ( 'link_category' == $taxonomy ) {
    233         /** This action is documented in wp-admin/edit-tags.php */
    234         do_action( 'edit_link_category_form', $tag );
     230    /** This action is documented in wp-admin/edit-tags.php */
     231    do_action( 'edit_link_category_form', $tag );
    235232} else {
    236         /**
    237         * Fires at the end of the Edit Term form.
    238         *
    239         * @since 2.5.0
    240         * @deprecated 3.0.0 Use {$taxonomy}_edit_form instead.
    241         *
    242         * @param object $tag Current taxonomy term object.
    243         */
    244         do_action( 'edit_tag_form', $tag );
     233    /**
     234    * Fires at the end of the Edit Term form.
     235    *
     236    * @since 2.5.0
     237    * @deprecated 3.0.0 Use {$taxonomy}_edit_form instead.
     238    *
     239    * @param object $tag Current taxonomy term object.
     240    */
     241    do_action( 'edit_tag_form', $tag );
    245242}
    246243/**
    247244 * Fires at the end of the Edit Term form for all taxonomies.
    do_action( "{$taxonomy}_edit_form", $tag, $taxonomy ); 
    258255
    259256<div class="edit-tag-actions">
    260257
    261         <?php submit_button( __( 'Update' ), 'primary', null, false ); ?>
     258    <?php submit_button( __( 'Update' ), 'primary', null, false ); ?>
    262259
    263         <?php if ( current_user_can( 'delete_term', $tag->term_id ) ) : ?>
    264                 <span id="delete-link">
    265                         <a class="delete" href="<?php echo admin_url( wp_nonce_url( "edit-tags.php?action=delete&taxonomy=$taxonomy&tag_ID=$tag->term_id", 'delete-tag_' . $tag->term_id ) ) ?>"><?php _e( 'Delete' ); ?></a>
    266                 </span>
    267         <?php endif; ?>
     260    <?php if ( current_user_can( 'delete_term', $tag->term_id ) ) : ?>
     261        <span id="delete-link">
     262            <a class="delete" href="<?php echo admin_url( wp_nonce_url( "edit-tags.php?action=delete&taxonomy=$taxonomy&tag_ID=$tag->term_id", 'delete-tag_' . $tag->term_id ) ) ?>"><?php _e( 'Delete' ); ?></a>
     263        </span>
     264    <?php endif; ?>
    268265
    269266</div>
    270267
  • src/wp-admin/includes/class-wp-links-list-table.php

    diff --git a/src/wp-admin/includes/class-wp-links-list-table.php b/src/wp-admin/includes/class-wp-links-list-table.php
    index 222d6dfc2d..97fd848e90 100644
    a b  
    1717 */
    1818class WP_Links_List_Table extends WP_List_Table {
    1919
    20         /**
    21         * Constructor.
    22         *
    23         * @since 3.1.0
    24         * @access public
    25         *
    26         * @see WP_List_Table::__construct() for more information on default arguments.
    27         *
    28         * @param array $args An associative array of arguments.
    29         */
    30         public function __construct( $args = array() ) {
    31                 parent::__construct( array(
    32                         'plural' => 'bookmarks',
    33                         'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
    34                 ) );
    35         }
     20    /**
     21    * Constructor.
     22    *
     23    * @since 3.1.0
     24    * @access public
     25    *
     26    * @see WP_List_Table::__construct() for more information on default arguments.
     27    *
     28    * @param array $args An associative array of arguments.
     29    */
     30    public function __construct( $args = array() ) {
     31        parent::__construct( array(
     32            'plural' => 'bookmarks',
     33            'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
     34        ) );
     35    }
    3636
    37         /**
    38         *
    39         * @return bool
    40         */
    41         public function ajax_user_can() {
    42                 return current_user_can( 'manage_links' );
    43         }
     37    /**
     38    *
     39    * @return bool
     40    */
     41    public function ajax_user_can() {
     42        return current_user_can( 'manage_links' );
     43    }
    4444
    45         /**
    46          *
    47          * @global int    $cat_id
    48          * @global string $s
    49          * @global string $orderby
    50          * @global string $order
    51          */
    52         public function prepare_items() {
    53                 global $cat_id, $s, $orderby, $order;
    5445
    55                 wp_reset_vars( array( 'action', 'cat_id', 'link_id', 'orderby', 'order', 's' ) );
     46    public function prepare_items() {
     47        $cat_id = wp_assign_request_var('cat_id');
     48        $s = wp_assign_request_var('s');
     49        $orderby = wp_assign_request_var('orderby');
     50        $order = wp_assign_request_var('order');
    5651
    57                 $args = array( 'hide_invisible' => 0, 'hide_empty' => 0 );
    5852
    59                 if ( 'all' != $cat_id )
    60                         $args['category'] = $cat_id;
    61                 if ( !empty( $s ) )
    62                         $args['search'] = $s;
    63                 if ( !empty( $orderby ) )
    64                         $args['orderby'] = $orderby;
    65                 if ( !empty( $order ) )
    66                         $args['order'] = $order;
     53        $args = array( 'hide_invisible' => 0, 'hide_empty' => 0 );
    6754
    68                 $this->items = get_bookmarks( $args );
    69         }
     55        if ( 'all' != $cat_id ) {
     56            $args['category'] = $cat_id;
     57        }
     58        if ( !empty( $s ) ) {
     59            $args['search'] = $s;
     60        }
     61        if ( !empty( $orderby ) ) {
     62            $args['orderby'] = $orderby;
     63        }
     64        if ( !empty( $order ) ) {
     65            $args['order'] = $order;
     66        }
    7067
    71         /**
    72          * @access public
    73          */
    74         public function no_items() {
    75                 _e( 'No links found.' );
    76         }
     68        $this->items = get_bookmarks( $args );
     69    }
    7770
    78         /**
    79          *
    80          * @return array
    81          */
    82         protected function get_bulk_actions() {
    83                 $actions = array();
    84                 $actions['delete'] = __( 'Delete' );
     71    /**
     72     * @access public
     73     */
     74    public function no_items() {
     75        _e( 'No links found.' );
     76    }
    8577
    86                 return $actions;
    87         }
     78    /**
     79     *
     80     * @return array
     81     */
     82    protected function get_bulk_actions() {
     83        $actions = array();
     84        $actions['delete'] = __( 'Delete' );
    8885
    89         /**
    90          *
    91          * @global int $cat_id
    92          * @param string $which
    93          */
    94         protected function extra_tablenav( $which ) {
    95                 global $cat_id;
     86        return $actions;
     87    }
    9688
    97                 if ( 'top' != $which )
    98                         return;
     89    /**
     90     *
     91     * @global int $cat_id
     92     * @param string $which
     93     */
     94    protected function extra_tablenav( $which ) {
     95        global $cat_id;
     96
     97        if ( 'top' != $which )
     98            return;
    9999?>
    100                 <div class="alignleft actions">
     100        <div class="alignleft actions">
    101101<?php
    102                         $dropdown_options = array(
    103                                 'selected' => $cat_id,
    104                                 'name' => 'cat_id',
    105                                 'taxonomy' => 'link_category',
    106                                 'show_option_all' => get_taxonomy( 'link_category' )->labels->all_items,
    107                                 'hide_empty' => true,
    108                                 'hierarchical' => 1,
    109                                 'show_count' => 0,
    110                                 'orderby' => 'name',
    111                         );
     102            $dropdown_options = array(
     103                'selected' => $cat_id,
     104                'name' => 'cat_id',
     105                'taxonomy' => 'link_category',
     106                'show_option_all' => get_taxonomy( 'link_category' )->labels->all_items,
     107                'hide_empty' => true,
     108                'hierarchical' => 1,
     109                'show_count' => 0,
     110                'orderby' => 'name',
     111            );
    112112
    113                         echo '<label class="screen-reader-text" for="cat_id">' . __( 'Filter by category' ) . '</label>';
    114                         wp_dropdown_categories( $dropdown_options );
    115                         submit_button( __( 'Filter' ), '', 'filter_action', false, array( 'id' => 'post-query-submit' ) );
     113            echo '<label class="screen-reader-text" for="cat_id">' . __( 'Filter by category' ) . '</label>';
     114            wp_dropdown_categories( $dropdown_options );
     115            submit_button( __( 'Filter' ), '', 'filter_action', false, array( 'id' => 'post-query-submit' ) );
    116116?>
    117                 </div>
     117        </div>
    118118<?php
    119         }
     119    }
    120120
    121         /**
    122         *
    123         * @return array
    124         */
    125         public function get_columns() {
    126                 return array(
    127                         'cb'         => '<input type="checkbox" />',
    128                         'name'       => _x( 'Name', 'link name' ),
    129                         'url'        => __( 'URL' ),
    130                         'categories' => __( 'Categories' ),
    131                         'rel'        => __( 'Relationship' ),
    132                         'visible'    => __( 'Visible' ),
    133                         'rating'     => __( 'Rating' )
    134                 );
    135         }
     121    /**
     122    *
     123    * @return array
     124    */
     125    public function get_columns() {
     126        return array(
     127            'cb'         => '<input type="checkbox" />',
     128            'name'       => _x( 'Name', 'link name' ),
     129            'url'        => __( 'URL' ),
     130            'categories' => __( 'Categories' ),
     131            'rel'        => __( 'Relationship' ),
     132            'visible'    => __( 'Visible' ),
     133            'rating'     => __( 'Rating' )
     134        );
     135    }
    136136
    137         /**
    138         *
    139         * @return array
    140         */
    141         protected function get_sortable_columns() {
    142                 return array(
    143                         'name'    => 'name',
    144                         'url'     => 'url',
    145                         'visible' => 'visible',
    146                         'rating'  => 'rating'
    147                 );
    148         }
     137    /**
     138    *
     139    * @return array
     140    */
     141    protected function get_sortable_columns() {
     142        return array(
     143            'name'    => 'name',
     144            'url'     => 'url',
     145            'visible' => 'visible',
     146            'rating'  => 'rating'
     147        );
     148    }
    149149
    150         /**
    151         * Get the name of the default primary column.
    152         *
    153         * @since 4.3.0
    154         * @access protected
    155         *
    156         * @return string Name of the default primary column, in this case, 'name'.
    157         */
    158         protected function get_default_primary_column_name() {
    159                 return 'name';
    160         }
     150    /**
     151    * Get the name of the default primary column.
     152    *
     153    * @since 4.3.0
     154    * @access protected
     155    *
     156    * @return string Name of the default primary column, in this case, 'name'.
     157    */
     158    protected function get_default_primary_column_name() {
     159        return 'name';
     160    }
    161161
    162         /**
    163         * Handles the checkbox column output.
    164         *
    165         * @since 4.3.0
    166         * @access public
    167         *
    168         * @param object $link The current link object.
    169         */
    170         public function column_cb( $link ) {
    171                 ?>
    172                 <label class="screen-reader-text" for="cb-select-<?php echo $link->link_id; ?>"><?php echo sprintf( __( 'Select %s' ), $link->link_name ); ?></label>
    173                 <input type="checkbox" name="linkcheck[]" id="cb-select-<?php echo $link->link_id; ?>" value="<?php echo esc_attr( $link->link_id ); ?>" />
    174                 <?php
    175         }
     162    /**
     163    * Handles the checkbox column output.
     164    *
     165    * @since 4.3.0
     166    * @access public
     167    *
     168    * @param object $link The current link object.
     169    */
     170    public function column_cb( $link ) {
     171        ?>
     172        <label class="screen-reader-text" for="cb-select-<?php echo $link->link_id; ?>"><?php echo sprintf( __( 'Select %s' ), $link->link_name ); ?></label>
     173        <input type="checkbox" name="linkcheck[]" id="cb-select-<?php echo $link->link_id; ?>" value="<?php echo esc_attr( $link->link_id ); ?>" />
     174        <?php
     175    }
    176176
    177         /**
    178         * Handles the link name column output.
    179         *
    180         * @since 4.3.0
    181         * @access public
    182         *
    183         * @param object $link The current link object.
    184         */
    185         public function column_name( $link ) {
    186                 $edit_link = get_edit_bookmark_link( $link );
    187                 printf( '<strong><a class="row-title" href="%s" aria-label="%s">%s</a></strong>',
    188                         $edit_link,
    189                         /* translators: %s: link name */
    190                         esc_attr( sprintf( __( 'Edit &#8220;%s&#8221;' ), $link->link_name ) ),
    191                         $link->link_name
    192                 );
    193         }
     177    /**
     178    * Handles the link name column output.
     179    *
     180    * @since 4.3.0
     181    * @access public
     182    *
     183    * @param object $link The current link object.
     184    */
     185    public function column_name( $link ) {
     186        $edit_link = get_edit_bookmark_link( $link );
     187        printf( '<strong><a class="row-title" href="%s" aria-label="%s">%s</a></strong>',
     188            $edit_link,
     189            /* translators: %s: link name */
     190            esc_attr( sprintf( __( 'Edit &#8220;%s&#8221;' ), $link->link_name ) ),
     191            $link->link_name
     192        );
     193    }
    194194
    195         /**
    196         * Handles the link URL column output.
    197         *
    198         * @since 4.3.0
    199         * @access public
    200         *
    201         * @param object $link The current link object.
    202         */
    203         public function column_url( $link ) {
    204                 $short_url = url_shorten( $link->link_url );
    205                 echo "<a href='$link->link_url'>$short_url</a>";
    206         }
     195    /**
     196    * Handles the link URL column output.
     197    *
     198    * @since 4.3.0
     199    * @access public
     200    *
     201    * @param object $link The current link object.
     202    */
     203    public function column_url( $link ) {
     204        $short_url = url_shorten( $link->link_url );
     205        echo "<a href='$link->link_url'>$short_url</a>";
     206    }
    207207
    208         /**
    209         * Handles the link categories column output.
    210         *
    211         * @since 4.3.0
    212         * @access public
    213         *
    214         * @global $cat_id
    215         *
    216         * @param object $link The current link object.
    217         */
    218         public function column_categories( $link ) {
    219                 global $cat_id;
     208    /**
     209    * Handles the link categories column output.
     210    *
     211    * @since 4.3.0
     212    * @access public
     213    *
     214    * @global $cat_id
     215    *
     216    * @param object $link The current link object.
     217    */
     218    public function column_categories( $link ) {
     219        global $cat_id;
    220220
    221                 $cat_names = array();
    222                 foreach ( $link->link_category as $category ) {
    223                         $cat = get_term( $category, 'link_category', OBJECT, 'display' );
    224                         if ( is_wp_error( $cat ) ) {
    225                                 echo $cat->get_error_message();
    226                         }
    227                         $cat_name = $cat->name;
    228                         if ( $cat_id != $category ) {
    229                                 $cat_name = "<a href='link-manager.php?cat_id=$category'>$cat_name</a>";
    230                         }
    231                         $cat_names[] = $cat_name;
    232                 }
    233                 echo implode( ', ', $cat_names );
    234         }
     221        $cat_names = array();
     222        foreach ( $link->link_category as $category ) {
     223            $cat = get_term( $category, 'link_category', OBJECT, 'display' );
     224            if ( is_wp_error( $cat ) ) {
     225                echo $cat->get_error_message();
     226            }
     227            $cat_name = $cat->name;
     228            if ( $cat_id != $category ) {
     229                $cat_name = "<a href='link-manager.php?cat_id=$category'>$cat_name</a>";
     230            }
     231            $cat_names[] = $cat_name;
     232        }
     233        echo implode( ', ', $cat_names );
     234    }
    235235
    236         /**
    237         * Handles the link relation column output.
    238         *
    239         * @since 4.3.0
    240         * @access public
    241         *
    242         * @param object $link The current link object.
    243         */
    244         public function column_rel( $link ) {
    245                 echo empty( $link->link_rel ) ? '<br />' : $link->link_rel;
    246         }
     236    /**
     237    * Handles the link relation column output.
     238    *
     239    * @since 4.3.0
     240    * @access public
     241    *
     242    * @param object $link The current link object.
     243    */
     244    public function column_rel( $link ) {
     245        echo empty( $link->link_rel ) ? '<br />' : $link->link_rel;
     246    }
    247247
    248         /**
    249         * Handles the link visibility column output.
    250         *
    251         * @since 4.3.0
    252         * @access public
    253         *
    254         * @param object $link The current link object.
    255         */
    256         public function column_visible( $link ) {
    257                 if ( 'Y' === $link->link_visible ) {
    258                         _e( 'Yes' );
    259                 } else {
    260                         _e( 'No' );
    261                 }
    262         }
     248    /**
     249    * Handles the link visibility column output.
     250    *
     251    * @since 4.3.0
     252    * @access public
     253    *
     254    * @param object $link The current link object.
     255    */
     256    public function column_visible( $link ) {
     257        if ( 'Y' === $link->link_visible ) {
     258            _e( 'Yes' );
     259        } else {
     260            _e( 'No' );
     261        }
     262    }
    263263
    264         /**
    265         * Handles the link rating column output.
    266         *
    267         * @since 4.3.0
    268         * @access public
    269         *
    270         * @param object $link The current link object.
    271         */
    272         public function column_rating( $link ) {
    273                 echo $link->link_rating;
    274         }
     264    /**
     265    * Handles the link rating column output.
     266    *
     267    * @since 4.3.0
     268    * @access public
     269    *
     270    * @param object $link The current link object.
     271    */
     272    public function column_rating( $link ) {
     273        echo $link->link_rating;
     274    }
    275275
    276         /**
    277         * Handles the default column output.
    278         *
    279         * @since 4.3.0
    280         * @access public
    281         *
    282         * @param object $link        Link object.
    283         * @param string $column_name Current column name.
    284         */
    285         public function column_default( $link, $column_name ) {
    286                 /**
    287                 * Fires for each registered custom link column.
    288                 *
    289                 * @since 2.1.0
    290                 *
    291                 * @param string $column_name Name of the custom column.
    292                 * @param int    $link_id     Link ID.
    293                 */
    294                 do_action( 'manage_link_custom_column', $column_name, $link->link_id );
    295         }
     276    /**
     277    * Handles the default column output.
     278    *
     279    * @since 4.3.0
     280    * @access public
     281    *
     282    * @param object $link        Link object.
     283    * @param string $column_name Current column name.
     284    */
     285    public function column_default( $link, $column_name ) {
     286        /**
     287        * Fires for each registered custom link column.
     288        *
     289        * @since 2.1.0
     290        *
     291        * @param string $column_name Name of the custom column.
     292        * @param int    $link_id     Link ID.
     293        */
     294        do_action( 'manage_link_custom_column', $column_name, $link->link_id );
     295    }
    296296
    297         public function display_rows() {
    298                 foreach ( $this->items as $link ) {
    299                         $link = sanitize_bookmark( $link );
    300                         $link->link_name = esc_attr( $link->link_name );
    301                         $link->link_category = wp_get_link_cats( $link->link_id );
     297    public function display_rows() {
     298        foreach ( $this->items as $link ) {
     299            $link = sanitize_bookmark( $link );
     300            $link->link_name = esc_attr( $link->link_name );
     301            $link->link_category = wp_get_link_cats( $link->link_id );
    302302?>
    303                 <tr id="link-<?php echo $link->link_id; ?>">
    304                         <?php $this->single_row_columns( $link ) ?>
    305                 </tr>
     303        <tr id="link-<?php echo $link->link_id; ?>">
     304            <?php $this->single_row_columns( $link ) ?>
     305        </tr>
    306306<?php
    307                 }
    308         }
     307        }
     308    }
    309309
    310         /**
    311         * Generates and displays row action links.
    312         *
    313         * @since 4.3.0
    314         * @access protected
    315         *
    316         * @param object $link        Link being acted upon.
    317         * @param string $column_name Current column name.
    318         * @param string $primary     Primary column name.
    319         * @return string Row action output for links.
    320         */
    321         protected function handle_row_actions( $link, $column_name, $primary ) {
    322                 if ( $primary !== $column_name ) {
    323                         return '';
    324                 }
     310    /**
     311    * Generates and displays row action links.
     312    *
     313    * @since 4.3.0
     314    * @access protected
     315    *
     316    * @param object $link        Link being acted upon.
     317    * @param string $column_name Current column name.
     318    * @param string $primary     Primary column name.
     319    * @return string Row action output for links.
     320    */
     321    protected function handle_row_actions( $link, $column_name, $primary ) {
     322        if ( $primary !== $column_name ) {
     323            return '';
     324        }
    325325
    326                 $edit_link = get_edit_bookmark_link( $link );
     326        $edit_link = get_edit_bookmark_link( $link );
    327327
    328                 $actions = array();
    329                 $actions['edit'] = '<a href="' . $edit_link . '">' . __('Edit') . '</a>';
    330                 $actions['delete'] = "<a class='submitdelete' href='" . wp_nonce_url("link.php?action=delete&amp;link_id=$link->link_id", 'delete-bookmark_' . $link->link_id) . "' onclick=\"if ( confirm( '" . esc_js(sprintf(__("You are about to delete this link '%s'\n  'Cancel' to stop, 'OK' to delete."), $link->link_name)) . "' ) ) { return true;}return false;\">" . __('Delete') . "</a>";
    331                 return $this->row_actions( $actions );
    332         }
     328        $actions = array();
     329        $actions['edit'] = '<a href="' . $edit_link . '">' . __('Edit') . '</a>';
     330        $actions['delete'] = "<a class='submitdelete' href='" . wp_nonce_url("link.php?action=delete&amp;link_id=$link->link_id", 'delete-bookmark_' . $link->link_id) . "' onclick=\"if ( confirm( '" . esc_js(sprintf(__("You are about to delete this link '%s'\n  'Cancel' to stop, 'OK' to delete."), $link->link_name)) . "' ) ) { return true;}return false;\">" . __('Delete') . "</a>";
     331        return $this->row_actions( $actions );
     332    }
    333333}
  • src/wp-admin/includes/class-wp-ms-themes-list-table.php

    diff --git a/src/wp-admin/includes/class-wp-ms-themes-list-table.php b/src/wp-admin/includes/class-wp-ms-themes-list-table.php
    index 0f3865a985..0104da97a0 100644
    a b  
    1717 */
    1818class WP_MS_Themes_List_Table extends WP_List_Table {
    1919
    20         public $site_id;
    21         public $is_site_themes;
    22 
    23         private $has_items;
    24 
    25         /**
    26          * Constructor.
    27          *
    28          * @since 3.1.0
    29          * @access public
    30          *
    31          * @see WP_List_Table::__construct() for more information on default arguments.
    32          *
    33          * @global string $status
    34          * @global int    $page
    35          *
    36          * @param array $args An associative array of arguments.
    37          */
    38         public function __construct( $args = array() ) {
    39                 global $status, $page;
    40 
    41                 parent::__construct( array(
    42                         'plural' => 'themes',
    43                         'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
    44                 ) );
    45 
    46                 $status = isset( $_REQUEST['theme_status'] ) ? $_REQUEST['theme_status'] : 'all';
    47                 if ( !in_array( $status, array( 'all', 'enabled', 'disabled', 'upgrade', 'search', 'broken' ) ) )
    48                         $status = 'all';
    49 
    50                 $page = $this->get_pagenum();
    51 
    52                 $this->is_site_themes = ( 'site-themes-network' === $this->screen->id ) ? true : false;
    53 
    54                 if ( $this->is_site_themes )
    55                         $this->site_id = isset( $_REQUEST['id'] ) ? intval( $_REQUEST['id'] ) : 0;
    56         }
    57 
    58         /**
    59          *
    60          * @return array
    61          */
    62         protected function get_table_classes() {
    63                 // todo: remove and add CSS for .themes
    64                 return array( 'widefat', 'plugins' );
    65         }
    66 
    67         /**
    68          *
    69          * @return bool
    70          */
    71         public function ajax_user_can() {
    72                 if ( $this->is_site_themes )
    73                         return current_user_can( 'manage_sites' );
    74                 else
    75                         return current_user_can( 'manage_network_themes' );
    76         }
    77 
    78         /**
    79          *
    80          * @global string $status
    81          * @global array $totals
    82          * @global int $page
    83          * @global string $orderby
    84          * @global string $order
    85          * @global string $s
    86          */
    87         public function prepare_items() {
    88                 global $status, $totals, $page, $orderby, $order, $s;
    89 
    90                 wp_reset_vars( array( 'orderby', 'order', 's' ) );
    91 
    92                 $themes = array(
    93                         /**
    94                          * Filters the full array of WP_Theme objects to list in the Multisite
    95                          * themes list table.
    96                          *
    97                          * @since 3.1.0
    98                          *
    99                          * @param array $all An array of WP_Theme objects to display in the list table.
    100                          */
    101                         'all' => apply_filters( 'all_themes', wp_get_themes() ),
    102                         'search' => array(),
    103                         'enabled' => array(),
    104                         'disabled' => array(),
    105                         'upgrade' => array(),
    106                         'broken' => $this->is_site_themes ? array() : wp_get_themes( array( 'errors' => true ) ),
    107                 );
    108 
    109                 if ( $this->is_site_themes ) {
    110                         $themes_per_page = $this->get_items_per_page( 'site_themes_network_per_page' );
    111                         $allowed_where = 'site';
    112                 } else {
    113                         $themes_per_page = $this->get_items_per_page( 'themes_network_per_page' );
    114                         $allowed_where = 'network';
    115                 }
    116 
    117                 $maybe_update = current_user_can( 'update_themes' ) && ! $this->is_site_themes && $current = get_site_transient( 'update_themes' );
    118 
    119                 foreach ( (array) $themes['all'] as $key => $theme ) {
    120                         if ( $this->is_site_themes && $theme->is_allowed( 'network' ) ) {
    121                                 unset( $themes['all'][ $key ] );
    122                                 continue;
    123                         }
    124 
    125                         if ( $maybe_update && isset( $current->response[ $key ] ) ) {
    126                                 $themes['all'][ $key ]->update = true;
    127                                 $themes['upgrade'][ $key ] = $themes['all'][ $key ];
    128                         }
    129 
    130                         $filter = $theme->is_allowed( $allowed_where, $this->site_id ) ? 'enabled' : 'disabled';
    131                         $themes[ $filter ][ $key ] = $themes['all'][ $key ];
    132                 }
    133 
    134                 if ( $s ) {
    135                         $status = 'search';
    136                         $themes['search'] = array_filter( array_merge( $themes['all'], $themes['broken'] ), array( $this, '_search_callback' ) );
    137                 }
    138 
    139                 $totals = array();
    140                 foreach ( $themes as $type => $list )
    141                         $totals[ $type ] = count( $list );
    142 
    143                 if ( empty( $themes[ $status ] ) && !in_array( $status, array( 'all', 'search' ) ) )
    144                         $status = 'all';
    145 
    146                 $this->items = $themes[ $status ];
    147                 WP_Theme::sort_by_name( $this->items );
    148 
    149                 $this->has_items = ! empty( $themes['all'] );
    150                 $total_this_page = $totals[ $status ];
    151 
    152                 wp_localize_script( 'updates', '_wpUpdatesItemCounts', array(
    153                         'themes' => $totals,
    154                         'totals' => wp_get_update_data(),
    155                 ) );
    156 
    157                 if ( $orderby ) {
    158                         $orderby = ucfirst( $orderby );
    159                         $order = strtoupper( $order );
    160 
    161                         if ( $orderby === 'Name' ) {
    162                                 if ( 'ASC' === $order ) {
    163                                         $this->items = array_reverse( $this->items );
    164                                 }
    165                         } else {
    166                                 uasort( $this->items, array( $this, '_order_callback' ) );
    167                         }
    168                 }
    169 
    170                 $start = ( $page - 1 ) * $themes_per_page;
    171 
    172                 if ( $total_this_page > $themes_per_page )
    173                         $this->items = array_slice( $this->items, $start, $themes_per_page, true );
    174 
    175                 $this->set_pagination_args( array(
    176                         'total_items' => $total_this_page,
    177                         'per_page' => $themes_per_page,
    178                 ) );
    179         }
    180 
    181         /**
    182          * @staticvar string $term
    183          * @param WP_Theme $theme
    184          * @return bool
    185          */
    186         public function _search_callback( $theme ) {
    187                 static $term = null;
    188                 if ( is_null( $term ) )
    189                         $term = wp_unslash( $_REQUEST['s'] );
    190 
    191                 foreach ( array( 'Name', 'Description', 'Author', 'Author', 'AuthorURI' ) as $field ) {
    192                         // Don't mark up; Do translate.
    193                         if ( false !== stripos( $theme->display( $field, false, true ), $term ) )
    194                                 return true;
    195                 }
    196 
    197                 if ( false !== stripos( $theme->get_stylesheet(), $term ) )
    198                         return true;
    199 
    200                 if ( false !== stripos( $theme->get_template(), $term ) )
    201                         return true;
    202 
    203                 return false;
    204         }
    205 
    206         // Not used by any core columns.
    207         /**
    208          * @global string $orderby
    209          * @global string $order
    210          * @param array $theme_a
    211          * @param array $theme_b
    212          * @return int
    213          */
    214         public function _order_callback( $theme_a, $theme_b ) {
    215                 global $orderby, $order;
    216 
    217                 $a = $theme_a[ $orderby ];
    218                 $b = $theme_b[ $orderby ];
    219 
    220                 if ( $a == $b )
    221                         return 0;
    222 
    223                 if ( 'DESC' === $order )
    224                         return ( $a < $b ) ? 1 : -1;
    225                 else
    226                         return ( $a < $b ) ? -1 : 1;
    227         }
    228 
    229         /**
    230          * @access public
    231          */
    232         public function no_items() {
    233                 if ( $this->has_items ) {
    234                         _e( 'No themes found.' );
    235                 } else {
    236                         _e( 'You do not appear to have any themes available at this time.' );
    237                 }
    238         }
    239 
    240         /**
    241          *
    242          * @return array
    243          */
    244         public function get_columns() {
    245                 return array(
    246                         'cb'          => '<input type="checkbox" />',
    247                         'name'        => __( 'Theme' ),
    248                         'description' => __( 'Description' ),
    249                 );
    250         }
    251 
    252         /**
    253          *
    254          * @return array
    255          */
    256         protected function get_sortable_columns() {
    257                 return array(
    258                         'name'         => 'name',
    259                 );
    260         }
    261 
    262         /**
    263          * Gets the name of the primary column.
    264          *
    265          * @since 4.3.0
    266          * @access protected
    267          *
    268          * @return string Unalterable name of the primary column name, in this case, 'name'.
    269          */
    270         protected function get_primary_column_name() {
    271                 return 'name';
    272         }
    273 
    274         /**
    275          *
    276          * @global array $totals
    277          * @global string $status
    278          * @return array
    279          */
    280         protected function get_views() {
    281                 global $totals, $status;
    282 
    283                 $status_links = array();
    284                 foreach ( $totals as $type => $count ) {
    285                         if ( !$count )
    286                                 continue;
    287 
    288                         switch ( $type ) {
    289                                 case 'all':
    290                                         $text = _nx( 'All <span class="count">(%s)</span>', 'All <span class="count">(%s)</span>', $count, 'themes' );
    291                                         break;
    292                                 case 'enabled':
    293                                         $text = _n( 'Enabled <span class="count">(%s)</span>', 'Enabled <span class="count">(%s)</span>', $count );
    294                                         break;
    295                                 case 'disabled':
    296                                         $text = _n( 'Disabled <span class="count">(%s)</span>', 'Disabled <span class="count">(%s)</span>', $count );
    297                                         break;
    298                                 case 'upgrade':
    299                                         $text = _n( 'Update Available <span class="count">(%s)</span>', 'Update Available <span class="count">(%s)</span>', $count );
    300                                         break;
    301                                 case 'broken' :
    302                                         $text = _n( 'Broken <span class="count">(%s)</span>', 'Broken <span class="count">(%s)</span>', $count );
    303                                         break;
    304                         }
    305 
    306                         if ( $this->is_site_themes )
    307                                 $url = 'site-themes.php?id=' . $this->site_id;
    308                         else
    309                                 $url = 'themes.php';
    310 
    311                         if ( 'search' != $type ) {
    312                                 $status_links[$type] = sprintf( "<a href='%s' %s>%s</a>",
    313                                         esc_url( add_query_arg('theme_status', $type, $url) ),
    314                                         ( $type === $status ) ? ' class="current"' : '',
    315                                         sprintf( $text, number_format_i18n( $count ) )
    316                                 );
    317                         }
    318                 }
    319 
    320                 return $status_links;
    321         }
    322 
    323         /**
    324          * @global string $status
    325          *
    326          * @return array
    327          */
    328         protected function get_bulk_actions() {
    329                 global $status;
    330 
    331                 $actions = array();
    332                 if ( 'enabled' != $status )
    333                         $actions['enable-selected'] = $this->is_site_themes ? __( 'Enable' ) : __( 'Network Enable' );
    334                 if ( 'disabled' != $status )
    335                         $actions['disable-selected'] = $this->is_site_themes ? __( 'Disable' ) : __( 'Network Disable' );
    336                 if ( ! $this->is_site_themes ) {
    337                         if ( current_user_can( 'update_themes' ) )
    338                                 $actions['update-selected'] = __( 'Update' );
    339                         if ( current_user_can( 'delete_themes' ) )
    340                                 $actions['delete-selected'] = __( 'Delete' );
    341                 }
    342                 return $actions;
    343         }
    344 
    345         /**
    346          * @access public
    347          */
    348         public function display_rows() {
    349                 foreach ( $this->items as $theme )
    350                         $this->single_row( $theme );
    351         }
    352 
    353         /**
    354          * Handles the checkbox column output.
    355          *
    356          * @since 4.3.0
    357          * @access public
    358          *
    359          * @param WP_Theme $theme The current WP_Theme object.
    360          */
    361         public function column_cb( $theme ) {
    362                 $checkbox_id = 'checkbox_' . md5( $theme->get('Name') );
    363                 ?>
    364                 <input type="checkbox" name="checked[]" value="<?php echo esc_attr( $theme->get_stylesheet() ) ?>" id="<?php echo $checkbox_id ?>" />
    365                 <label class="screen-reader-text" for="<?php echo $checkbox_id ?>" ><?php _e( 'Select' ) ?>  <?php echo $theme->display( 'Name' ) ?></label>
    366                 <?php
    367         }
    368 
    369         /**
    370          * Handles the name column output.
    371          *
    372          * @since 4.3.0
    373          * @access public
    374          *
    375          * @global string $status
    376          * @global int    $page
    377          * @global string $s
    378          *
    379          * @param WP_Theme $theme The current WP_Theme object.
    380          */
    381         public function column_name( $theme ) {
    382                 global $status, $page, $s;
    383 
    384                 $context = $status;
    385 
    386                 if ( $this->is_site_themes ) {
    387                         $url = "site-themes.php?id={$this->site_id}&amp;";
    388                         $allowed = $theme->is_allowed( 'site', $this->site_id );
    389                 } else {
    390                         $url = 'themes.php?';
    391                         $allowed = $theme->is_allowed( 'network' );
    392                 }
    393 
    394                 // Pre-order.
    395                 $actions = array(
    396                         'enable' => '',
    397                         'disable' => '',
    398                         'edit' => '',
    399                         'delete' => ''
    400                 );
    401 
    402                 $stylesheet = $theme->get_stylesheet();
    403                 $theme_key = urlencode( $stylesheet );
    404 
    405                 if ( ! $allowed ) {
    406                         if ( ! $theme->errors() ) {
    407                                 $url = add_query_arg( array(
    408                                         'action' => 'enable',
    409                                         'theme'  => $theme_key,
    410                                         'paged'  => $page,
    411                                         's'      => $s,
    412                                 ), $url );
    413 
    414                                 if ( $this->is_site_themes ) {
    415                                         /* translators: %s: theme name */
    416                                         $aria_label = sprintf( __( 'Enable %s' ), $theme->display( 'Name' ) );
    417                                 } else {
    418                                         /* translators: %s: theme name */
    419                                         $aria_label = sprintf( __( 'Network Enable %s' ), $theme->display( 'Name' ) );
    420                                 }
    421 
    422                                 $actions['enable'] = sprintf( '<a href="%s" class="edit" aria-label="%s">%s</a>',
    423                                         esc_url( wp_nonce_url( $url, 'enable-theme_' . $stylesheet ) ),
    424                                         esc_attr( $aria_label ),
    425                                         ( $this->is_site_themes ? __( 'Enable' ) : __( 'Network Enable' ) )
    426                                 );
    427                         }
    428                 } else {
    429                         $url = add_query_arg( array(
    430                                 'action' => 'disable',
    431                                 'theme'  => $theme_key,
    432                                 'paged'  => $page,
    433                                 's'      => $s,
    434                         ), $url );
    435 
    436                         if ( $this->is_site_themes ) {
    437                                 /* translators: %s: theme name */
    438                                 $aria_label = sprintf( __( 'Disable %s' ), $theme->display( 'Name' ) );
    439                         } else {
    440                                 /* translators: %s: theme name */
    441                                 $aria_label = sprintf( __( 'Network Disable %s' ), $theme->display( 'Name' ) );
    442                         }
    443 
    444                         $actions['disable'] = sprintf( '<a href="%s" aria-label="%s">%s</a>',
    445                                 esc_url( wp_nonce_url( $url, 'disable-theme_' . $stylesheet ) ),
    446                                 esc_attr( $aria_label ),
    447                                 ( $this->is_site_themes ? __( 'Disable' ) : __( 'Network Disable' ) )
    448                         );
    449                 }
    450 
    451                 if ( current_user_can('edit_themes') ) {
    452                         $url = add_query_arg( array(
    453                                 'theme' => $theme_key,
    454                         ), 'theme-editor.php' );
    455 
    456                         /* translators: %s: theme name */
    457                         $aria_label = sprintf( __( 'Open %s in the Theme Editor' ), $theme->display( 'Name' ) );
    458 
    459                         $actions['edit'] = sprintf( '<a href="%s" class="edit" aria-label="%s">%s</a>',
    460                                 esc_url( $url ),
    461                                 esc_attr( $aria_label ),
    462                                 __( 'Edit' )
    463                         );
    464                 }
    465 
    466                 if ( ! $allowed && current_user_can( 'delete_themes' ) && ! $this->is_site_themes && $stylesheet != get_option( 'stylesheet' ) && $stylesheet != get_option( 'template' ) ) {
    467                         $url = add_query_arg( array(
    468                                 'action'       => 'delete-selected',
    469                                 'checked[]'    => $theme_key,
    470                                 'theme_status' => $context,
    471                                 'paged'        => $page,
    472                                 's'            => $s,
    473                         ), 'themes.php' );
    474 
    475                         /* translators: %s: theme name */
    476                         $aria_label = sprintf( _x( 'Delete %s', 'theme' ), $theme->display( 'Name' ) );
    477 
    478                         $actions['delete'] = sprintf( '<a href="%s" class="delete" aria-label="%s">%s</a>',
    479                                 esc_url( wp_nonce_url( $url, 'bulk-themes' ) ),
    480                                 esc_attr( $aria_label ),
    481                                 __( 'Delete' )
    482                         );
    483                 }
    484                 /**
    485                  * Filters the action links displayed for each theme in the Multisite
    486                  * themes list table.
    487                  *
    488                  * The action links displayed are determined by the theme's status, and
    489                  * which Multisite themes list table is being displayed - the Network
    490                  * themes list table (themes.php), which displays all installed themes,
    491                  * or the Site themes list table (site-themes.php), which displays the
    492                  * non-network enabled themes when editing a site in the Network admin.
    493                  *
    494                  * The default action links for the Network themes list table include
    495                  * 'Network Enable', 'Network Disable', 'Edit', and 'Delete'.
    496                  *
    497                  * The default action links for the Site themes list table include
    498                  * 'Enable', 'Disable', and 'Edit'.
    499                  *
    500                  * @since 2.8.0
    501                  *
    502                  * @param array    $actions An array of action links.
    503                  * @param WP_Theme $theme   The current WP_Theme object.
    504                  * @param string   $context Status of the theme.
    505                  */
    506                 $actions = apply_filters( 'theme_action_links', array_filter( $actions ), $theme, $context );
    507 
    508                 /**
    509                  * Filters the action links of a specific theme in the Multisite themes
    510                  * list table.
    511                  *
    512                  * The dynamic portion of the hook name, `$stylesheet`, refers to the
    513                  * directory name of the theme, which in most cases is synonymous
    514                  * with the template name.
    515                  *
    516                  * @since 3.1.0
    517                  *
    518                  * @param array    $actions An array of action links.
    519                  * @param WP_Theme $theme   The current WP_Theme object.
    520                  * @param string   $context Status of the theme.
    521                  */
    522                 $actions = apply_filters( "theme_action_links_{$stylesheet}", $actions, $theme, $context );
    523 
    524                 echo $this->row_actions( $actions, true );
    525         }
    526 
    527         /**
    528          * Handles the description column output.
    529          *
    530          * @since 4.3.0
    531          * @access public
    532          *
    533          * @global string $status
    534          * @global array  $totals
    535          *
    536          * @param WP_Theme $theme The current WP_Theme object.
    537          */
    538         public function column_description( $theme ) {
    539                 global $status, $totals;
    540                 if ( $theme->errors() ) {
    541                         $pre = $status === 'broken' ? __( 'Broken Theme:' ) . ' ' : '';
    542                         echo '<p><strong class="error-message">' . $pre . $theme->errors()->get_error_message() . '</strong></p>';
    543                 }
    544 
    545                 if ( $this->is_site_themes ) {
    546                         $allowed = $theme->is_allowed( 'site', $this->site_id );
    547                 } else {
    548                         $allowed = $theme->is_allowed( 'network' );
    549                 }
    550 
    551                 $class = ! $allowed ? 'inactive' : 'active';
    552                 if ( ! empty( $totals['upgrade'] ) && ! empty( $theme->update ) )
    553                         $class .= ' update';
    554 
    555                 echo "<div class='theme-description'><p>" . $theme->display( 'Description' ) . "</p></div>
    556                         <div class='$class second theme-version-author-uri'>";
    557 
    558                 $stylesheet = $theme->get_stylesheet();
    559                 $theme_meta = array();
    560 
    561                 if ( $theme->get('Version') ) {
    562                         $theme_meta[] = sprintf( __( 'Version %s' ), $theme->display('Version') );
    563                 }
    564                 $theme_meta[] = sprintf( __( 'By %s' ), $theme->display('Author') );
    565 
    566                 if ( $theme->get('ThemeURI') ) {
    567                         /* translators: %s: theme name */
    568                         $aria_label = sprintf( __( 'Visit %s homepage' ), $theme->display( 'Name' ) );
    569 
    570                         $theme_meta[] = sprintf( '<a href="%s" aria-label="%s">%s</a>',
    571                                 $theme->display( 'ThemeURI' ),
    572                                 esc_attr( $aria_label ),
    573                                 __( 'Visit Theme Site' )
    574                         );
    575                 }
    576                 /**
    577                  * Filters the array of row meta for each theme in the Multisite themes
    578                  * list table.
    579                  *
    580                  * @since 3.1.0
    581                  *
    582                  * @param array    $theme_meta An array of the theme's metadata,
    583                  *                             including the version, author, and
    584                  *                             theme URI.
    585                  * @param string   $stylesheet Directory name of the theme.
    586                  * @param WP_Theme $theme      WP_Theme object.
    587                  * @param string   $status     Status of the theme.
    588                  */
    589                 $theme_meta = apply_filters( 'theme_row_meta', $theme_meta, $stylesheet, $theme, $status );
    590                 echo implode( ' | ', $theme_meta );
    591 
    592                 echo '</div>';
    593         }
    594 
    595         /**
    596          * Handles default column output.
    597          *
    598          * @since 4.3.0
    599          * @access public
    600          *
    601          * @param WP_Theme $theme       The current WP_Theme object.
    602          * @param string   $column_name The current column name.
    603          */
    604         public function column_default( $theme, $column_name ) {
    605                 $stylesheet = $theme->get_stylesheet();
    606 
    607                 /**
    608                  * Fires inside each custom column of the Multisite themes list table.
    609                  *
    610                  * @since 3.1.0
    611                  *
    612                  * @param string   $column_name Name of the column.
    613                  * @param string   $stylesheet  Directory name of the theme.
    614                  * @param WP_Theme $theme       Current WP_Theme object.
    615                  */
    616                 do_action( 'manage_themes_custom_column', $column_name, $stylesheet, $theme );
    617         }
    618 
    619         /**
    620          * Handles the output for a single table row.
    621          *
    622          * @since 4.3.0
    623          * @access public
    624          *
    625          * @param WP_Theme $item The current WP_Theme object.
    626          */
    627         public function single_row_columns( $item ) {
    628                 list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
    629 
    630                 foreach ( $columns as $column_name => $column_display_name ) {
    631                         $extra_classes = '';
    632                         if ( in_array( $column_name, $hidden ) ) {
    633                                 $extra_classes .= ' hidden';
    634                         }
    635 
    636                         switch ( $column_name ) {
    637                                 case 'cb':
    638                                         echo '<th scope="row" class="check-column">';
    639 
    640                                         $this->column_cb( $item );
    641 
    642                                         echo '</th>';
    643                                         break;
    644 
    645                                 case 'name':
    646                                         echo "<td class='theme-title column-primary{$extra_classes}'><strong>" . $item->display('Name') . "</strong>";
    647 
    648                                         $this->column_name( $item );
    649 
    650                                         echo "</td>";
    651                                         break;
    652 
    653                                 case 'description':
    654                                         echo "<td class='column-description desc{$extra_classes}'>";
    655 
    656                                         $this->column_description( $item );
    657 
    658                                         echo '</td>';
    659                                         break;
    660 
    661                                 default:
    662                                         echo "<td class='$column_name column-$column_name{$extra_classes}'>";
    663 
    664                                         $this->column_default( $item, $column_name );
    665 
    666                                         echo "</td>";
    667                                         break;
    668                         }
    669                 }
    670         }
    671 
    672         /**
    673          * @global string $status
    674          * @global array  $totals
    675          *
    676          * @param WP_Theme $theme
    677          */
    678         public function single_row( $theme ) {
    679                 global $status, $totals;
    680 
    681                 if ( $this->is_site_themes ) {
    682                         $allowed = $theme->is_allowed( 'site', $this->site_id );
    683                 } else {
    684                         $allowed = $theme->is_allowed( 'network' );
    685                 }
    686 
    687                 $stylesheet = $theme->get_stylesheet();
    688 
    689                 $class = ! $allowed ? 'inactive' : 'active';
    690                 if ( ! empty( $totals['upgrade'] ) && ! empty( $theme->update ) ) {
    691                         $class .= ' update';
    692                 }
    693 
    694                 printf( '<tr class="%s" data-slug="%s">',
    695                         esc_attr( $class ),
    696                         esc_attr( $stylesheet )
    697                 );
    698 
    699                 $this->single_row_columns( $theme );
    700 
    701                 echo "</tr>";
    702 
    703                 if ( $this->is_site_themes )
    704                         remove_action( "after_theme_row_$stylesheet", 'wp_theme_update_row' );
    705 
    706                 /**
    707                  * Fires after each row in the Multisite themes list table.
    708                  *
    709                  * @since 3.1.0
    710                  *
    711                  * @param string   $stylesheet Directory name of the theme.
    712                  * @param WP_Theme $theme      Current WP_Theme object.
    713                  * @param string   $status     Status of the theme.
    714                  */
    715                 do_action( 'after_theme_row', $stylesheet, $theme, $status );
    716 
    717                 /**
    718                  * Fires after each specific row in the Multisite themes list table.
    719                  *
    720                  * The dynamic portion of the hook name, `$stylesheet`, refers to the
    721                  * directory name of the theme, most often synonymous with the template
    722                  * name of the theme.
    723                  *
    724                  * @since 3.5.0
    725                  *
    726                  * @param string   $stylesheet Directory name of the theme.
    727                  * @param WP_Theme $theme      Current WP_Theme object.
    728                  * @param string   $status     Status of the theme.
    729                  */
    730                 do_action( "after_theme_row_{$stylesheet}", $stylesheet, $theme, $status );
    731         }
     20    public $site_id;
     21    public $is_site_themes;
     22
     23    private $has_items;
     24
     25    /**
     26     * Constructor.
     27     *
     28     * @since 3.1.0
     29     * @access public
     30     *
     31     * @see WP_List_Table::__construct() for more information on default arguments.
     32     *
     33     * @global string $status
     34     * @global int    $page
     35     *
     36     * @param array $args An associative array of arguments.
     37     */
     38    public function __construct( $args = array() ) {
     39        global $status, $page;
     40
     41        parent::__construct( array(
     42            'plural' => 'themes',
     43            'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
     44        ) );
     45
     46        $status = isset( $_REQUEST['theme_status'] ) ? $_REQUEST['theme_status'] : 'all';
     47        if ( !in_array( $status, array( 'all', 'enabled', 'disabled', 'upgrade', 'search', 'broken' ) ) )
     48            $status = 'all';
     49
     50        $page = $this->get_pagenum();
     51
     52        $this->is_site_themes = ( 'site-themes-network' === $this->screen->id ) ? true : false;
     53
     54        if ( $this->is_site_themes )
     55            $this->site_id = isset( $_REQUEST['id'] ) ? intval( $_REQUEST['id'] ) : 0;
     56    }
     57
     58    /**
     59     *
     60     * @return array
     61     */
     62    protected function get_table_classes() {
     63        // todo: remove and add CSS for .themes
     64        return array( 'widefat', 'plugins' );
     65    }
     66
     67    /**
     68     *
     69     * @return bool
     70     */
     71    public function ajax_user_can() {
     72        if ( $this->is_site_themes )
     73            return current_user_can( 'manage_sites' );
     74        else
     75            return current_user_can( 'manage_network_themes' );
     76    }
     77
     78    public function prepare_items() {
     79        $status = wp_assign_request_var('status');
     80        $total = wp_assign_request_var('total');
     81        $page = wp_assign_request_var('page');
     82        $orderby = wp_assign_request_var('orderby');
     83        $order = wp_assign_request_var('order');
     84        $s = wp_assign_request_var('s');
     85
     86        $themes = array(
     87            /**
     88             * Filters the full array of WP_Theme objects to list in the Multisite
     89             * themes list table.
     90             *
     91             * @since 3.1.0
     92             *
     93             * @param array $all An array of WP_Theme objects to display in the list table.
     94             */
     95            'all' => apply_filters( 'all_themes', wp_get_themes() ),
     96            'search' => array(),
     97            'enabled' => array(),
     98            'disabled' => array(),
     99            'upgrade' => array(),
     100            'broken' => $this->is_site_themes ? array() : wp_get_themes( array( 'errors' => true ) ),
     101        );
     102
     103        if ( $this->is_site_themes ) {
     104            $themes_per_page = $this->get_items_per_page( 'site_themes_network_per_page' );
     105            $allowed_where = 'site';
     106        } else {
     107            $themes_per_page = $this->get_items_per_page( 'themes_network_per_page' );
     108            $allowed_where = 'network';
     109        }
     110
     111        $maybe_update = current_user_can( 'update_themes' ) && ! $this->is_site_themes && $current = get_site_transient( 'update_themes' );
     112
     113        foreach ( (array) $themes['all'] as $key => $theme ) {
     114            if ( $this->is_site_themes && $theme->is_allowed( 'network' ) ) {
     115                unset( $themes['all'][ $key ] );
     116                continue;
     117            }
     118
     119            if ( $maybe_update && isset( $current->response[ $key ] ) ) {
     120                $themes['all'][ $key ]->update = true;
     121                $themes['upgrade'][ $key ] = $themes['all'][ $key ];
     122            }
     123
     124            $filter = $theme->is_allowed( $allowed_where, $this->site_id ) ? 'enabled' : 'disabled';
     125            $themes[ $filter ][ $key ] = $themes['all'][ $key ];
     126        }
     127
     128        if ( $s ) {
     129            $status = 'search';
     130            $themes['search'] = array_filter( array_merge( $themes['all'], $themes['broken'] ), array( $this, '_search_callback' ) );
     131        }
     132
     133        $totals = array();
     134        foreach ( $themes as $type => $list )
     135            $totals[ $type ] = count( $list );
     136
     137        if ( empty( $themes[ $status ] ) && !in_array( $status, array( 'all', 'search' ) ) )
     138            $status = 'all';
     139
     140        $this->items = $themes[ $status ];
     141        WP_Theme::sort_by_name( $this->items );
     142
     143        $this->has_items = ! empty( $themes['all'] );
     144        $total_this_page = $totals[ $status ];
     145
     146        wp_localize_script( 'updates', '_wpUpdatesItemCounts', array(
     147            'themes' => $totals,
     148            'totals' => wp_get_update_data(),
     149        ) );
     150
     151        if ( $orderby ) {
     152            $orderby = ucfirst( $orderby );
     153            $order = strtoupper( $order );
     154
     155            if ( $orderby === 'Name' ) {
     156                if ( 'ASC' === $order ) {
     157                    $this->items = array_reverse( $this->items );
     158                }
     159            } else {
     160                uasort( $this->items, array( $this, '_order_callback' ) );
     161            }
     162        }
     163
     164        $start = ( $page - 1 ) * $themes_per_page;
     165
     166        if ( $total_this_page > $themes_per_page )
     167            $this->items = array_slice( $this->items, $start, $themes_per_page, true );
     168
     169        $this->set_pagination_args( array(
     170            'total_items' => $total_this_page,
     171            'per_page' => $themes_per_page,
     172        ) );
     173    }
     174
     175    /**
     176     * @staticvar string $term
     177     * @param WP_Theme $theme
     178     * @return bool
     179     */
     180    public function _search_callback( $theme ) {
     181        static $term = null;
     182        if ( is_null( $term ) )
     183            $term = wp_unslash( $_REQUEST['s'] );
     184
     185        foreach ( array( 'Name', 'Description', 'Author', 'Author', 'AuthorURI' ) as $field ) {
     186            // Don't mark up; Do translate.
     187            if ( false !== stripos( $theme->display( $field, false, true ), $term ) )
     188                return true;
     189        }
     190
     191        if ( false !== stripos( $theme->get_stylesheet(), $term ) )
     192            return true;
     193
     194        if ( false !== stripos( $theme->get_template(), $term ) )
     195            return true;
     196
     197        return false;
     198    }
     199
     200    // Not used by any core columns.
     201    /**
     202     * @global string $orderby
     203     * @global string $order
     204     * @param array $theme_a
     205     * @param array $theme_b
     206     * @return int
     207     */
     208    public function _order_callback( $theme_a, $theme_b ) {
     209        global $orderby, $order;
     210
     211        $a = $theme_a[ $orderby ];
     212        $b = $theme_b[ $orderby ];
     213
     214        if ( $a == $b )
     215            return 0;
     216
     217        if ( 'DESC' === $order )
     218            return ( $a < $b ) ? 1 : -1;
     219        else
     220            return ( $a < $b ) ? -1 : 1;
     221    }
     222
     223    /**
     224     * @access public
     225     */
     226    public function no_items() {
     227        if ( $this->has_items ) {
     228            _e( 'No themes found.' );
     229        } else {
     230            _e( 'You do not appear to have any themes available at this time.' );
     231        }
     232    }
     233
     234    /**
     235     *
     236     * @return array
     237     */
     238    public function get_columns() {
     239        return array(
     240            'cb'          => '<input type="checkbox" />',
     241            'name'        => __( 'Theme' ),
     242            'description' => __( 'Description' ),
     243        );
     244    }
     245
     246    /**
     247     *
     248     * @return array
     249     */
     250    protected function get_sortable_columns() {
     251        return array(
     252            'name'         => 'name',
     253        );
     254    }
     255
     256    /**
     257     * Gets the name of the primary column.
     258     *
     259     * @since 4.3.0
     260     * @access protected
     261     *
     262     * @return string Unalterable name of the primary column name, in this case, 'name'.
     263     */
     264    protected function get_primary_column_name() {
     265        return 'name';
     266    }
     267
     268    /**
     269     *
     270     * @global array $totals
     271     * @global string $status
     272     * @return array
     273     */
     274    protected function get_views() {
     275        global $totals, $status;
     276
     277        $status_links = array();
     278        foreach ( $totals as $type => $count ) {
     279            if ( !$count )
     280                continue;
     281
     282            switch ( $type ) {
     283                case 'all':
     284                    $text = _nx( 'All <span class="count">(%s)</span>', 'All <span class="count">(%s)</span>', $count, 'themes' );
     285                    break;
     286                case 'enabled':
     287                    $text = _n( 'Enabled <span class="count">(%s)</span>', 'Enabled <span class="count">(%s)</span>', $count );
     288                    break;
     289                case 'disabled':
     290                    $text = _n( 'Disabled <span class="count">(%s)</span>', 'Disabled <span class="count">(%s)</span>', $count );
     291                    break;
     292                case 'upgrade':
     293                    $text = _n( 'Update Available <span class="count">(%s)</span>', 'Update Available <span class="count">(%s)</span>', $count );
     294                    break;
     295                case 'broken' :
     296                    $text = _n( 'Broken <span class="count">(%s)</span>', 'Broken <span class="count">(%s)</span>', $count );
     297                    break;
     298            }
     299
     300            if ( $this->is_site_themes )
     301                $url = 'site-themes.php?id=' . $this->site_id;
     302            else
     303                $url = 'themes.php';
     304
     305            if ( 'search' != $type ) {
     306                $status_links[$type] = sprintf( "<a href='%s' %s>%s</a>",
     307                    esc_url( add_query_arg('theme_status', $type, $url) ),
     308                    ( $type === $status ) ? ' class="current"' : '',
     309                    sprintf( $text, number_format_i18n( $count ) )
     310                );
     311            }
     312        }
     313
     314        return $status_links;
     315    }
     316
     317    /**
     318     * @global string $status
     319     *
     320     * @return array
     321     */
     322    protected function get_bulk_actions() {
     323        global $status;
     324
     325        $actions = array();
     326        if ( 'enabled' != $status )
     327            $actions['enable-selected'] = $this->is_site_themes ? __( 'Enable' ) : __( 'Network Enable' );
     328        if ( 'disabled' != $status )
     329            $actions['disable-selected'] = $this->is_site_themes ? __( 'Disable' ) : __( 'Network Disable' );
     330        if ( ! $this->is_site_themes ) {
     331            if ( current_user_can( 'update_themes' ) )
     332                $actions['update-selected'] = __( 'Update' );
     333            if ( current_user_can( 'delete_themes' ) )
     334                $actions['delete-selected'] = __( 'Delete' );
     335        }
     336        return $actions;
     337    }
     338
     339    /**
     340     * @access public
     341     */
     342    public function display_rows() {
     343        foreach ( $this->items as $theme )
     344            $this->single_row( $theme );
     345    }
     346
     347    /**
     348     * Handles the checkbox column output.
     349     *
     350     * @since 4.3.0
     351     * @access public
     352     *
     353     * @param WP_Theme $theme The current WP_Theme object.
     354     */
     355    public function column_cb( $theme ) {
     356        $checkbox_id = 'checkbox_' . md5( $theme->get('Name') );
     357        ?>
     358        <input type="checkbox" name="checked[]" value="<?php echo esc_attr( $theme->get_stylesheet() ) ?>" id="<?php echo $checkbox_id ?>" />
     359        <label class="screen-reader-text" for="<?php echo $checkbox_id ?>" ><?php _e( 'Select' ) ?>  <?php echo $theme->display( 'Name' ) ?></label>
     360        <?php
     361    }
     362
     363    /**
     364     * Handles the name column output.
     365     *
     366     * @since 4.3.0
     367     * @access public
     368     *
     369     * @global string $status
     370     * @global int    $page
     371     * @global string $s
     372     *
     373     * @param WP_Theme $theme The current WP_Theme object.
     374     */
     375    public function column_name( $theme ) {
     376        global $status, $page, $s;
     377
     378        $context = $status;
     379
     380        if ( $this->is_site_themes ) {
     381            $url = "site-themes.php?id={$this->site_id}&amp;";
     382            $allowed = $theme->is_allowed( 'site', $this->site_id );
     383        } else {
     384            $url = 'themes.php?';
     385            $allowed = $theme->is_allowed( 'network' );
     386        }
     387
     388        // Pre-order.
     389        $actions = array(
     390            'enable' => '',
     391            'disable' => '',
     392            'edit' => '',
     393            'delete' => ''
     394        );
     395
     396        $stylesheet = $theme->get_stylesheet();
     397        $theme_key = urlencode( $stylesheet );
     398
     399        if ( ! $allowed ) {
     400            if ( ! $theme->errors() ) {
     401                $url = add_query_arg( array(
     402                    'action' => 'enable',
     403                    'theme'  => $theme_key,
     404                    'paged'  => $page,
     405                    's'      => $s,
     406                ), $url );
     407
     408                if ( $this->is_site_themes ) {
     409                    /* translators: %s: theme name */
     410                    $aria_label = sprintf( __( 'Enable %s' ), $theme->display( 'Name' ) );
     411                } else {
     412                    /* translators: %s: theme name */
     413                    $aria_label = sprintf( __( 'Network Enable %s' ), $theme->display( 'Name' ) );
     414                }
     415
     416                $actions['enable'] = sprintf( '<a href="%s" class="edit" aria-label="%s">%s</a>',
     417                    esc_url( wp_nonce_url( $url, 'enable-theme_' . $stylesheet ) ),
     418                    esc_attr( $aria_label ),
     419                    ( $this->is_site_themes ? __( 'Enable' ) : __( 'Network Enable' ) )
     420                );
     421            }
     422        } else {
     423            $url = add_query_arg( array(
     424                'action' => 'disable',
     425                'theme'  => $theme_key,
     426                'paged'  => $page,
     427                's'      => $s,
     428            ), $url );
     429
     430            if ( $this->is_site_themes ) {
     431                /* translators: %s: theme name */
     432                $aria_label = sprintf( __( 'Disable %s' ), $theme->display( 'Name' ) );
     433            } else {
     434                /* translators: %s: theme name */
     435                $aria_label = sprintf( __( 'Network Disable %s' ), $theme->display( 'Name' ) );
     436            }
     437
     438            $actions['disable'] = sprintf( '<a href="%s" aria-label="%s">%s</a>',
     439                esc_url( wp_nonce_url( $url, 'disable-theme_' . $stylesheet ) ),
     440                esc_attr( $aria_label ),
     441                ( $this->is_site_themes ? __( 'Disable' ) : __( 'Network Disable' ) )
     442            );
     443        }
     444
     445        if ( current_user_can('edit_themes') ) {
     446            $url = add_query_arg( array(
     447                'theme' => $theme_key,
     448            ), 'theme-editor.php' );
     449
     450            /* translators: %s: theme name */
     451            $aria_label = sprintf( __( 'Open %s in the Theme Editor' ), $theme->display( 'Name' ) );
     452
     453            $actions['edit'] = sprintf( '<a href="%s" class="edit" aria-label="%s">%s</a>',
     454                esc_url( $url ),
     455                esc_attr( $aria_label ),
     456                __( 'Edit' )
     457            );
     458        }
     459
     460        if ( ! $allowed && current_user_can( 'delete_themes' ) && ! $this->is_site_themes && $stylesheet != get_option( 'stylesheet' ) && $stylesheet != get_option( 'template' ) ) {
     461            $url = add_query_arg( array(
     462                'action'       => 'delete-selected',
     463                'checked[]'    => $theme_key,
     464                'theme_status' => $context,
     465                'paged'        => $page,
     466                's'            => $s,
     467            ), 'themes.php' );
     468
     469            /* translators: %s: theme name */
     470            $aria_label = sprintf( _x( 'Delete %s', 'theme' ), $theme->display( 'Name' ) );
     471
     472            $actions['delete'] = sprintf( '<a href="%s" class="delete" aria-label="%s">%s</a>',
     473                esc_url( wp_nonce_url( $url, 'bulk-themes' ) ),
     474                esc_attr( $aria_label ),
     475                __( 'Delete' )
     476            );
     477        }
     478        /**
     479         * Filters the action links displayed for each theme in the Multisite
     480         * themes list table.
     481         *
     482         * The action links displayed are determined by the theme's status, and
     483         * which Multisite themes list table is being displayed - the Network
     484         * themes list table (themes.php), which displays all installed themes,
     485         * or the Site themes list table (site-themes.php), which displays the
     486         * non-network enabled themes when editing a site in the Network admin.
     487         *
     488         * The default action links for the Network themes list table include
     489         * 'Network Enable', 'Network Disable', 'Edit', and 'Delete'.
     490         *
     491         * The default action links for the Site themes list table include
     492         * 'Enable', 'Disable', and 'Edit'.
     493         *
     494         * @since 2.8.0
     495         *
     496         * @param array    $actions An array of action links.
     497         * @param WP_Theme $theme   The current WP_Theme object.
     498         * @param string   $context Status of the theme.
     499         */
     500        $actions = apply_filters( 'theme_action_links', array_filter( $actions ), $theme, $context );
     501
     502        /**
     503         * Filters the action links of a specific theme in the Multisite themes
     504         * list table.
     505         *
     506         * The dynamic portion of the hook name, `$stylesheet`, refers to the
     507         * directory name of the theme, which in most cases is synonymous
     508         * with the template name.
     509         *
     510         * @since 3.1.0
     511         *
     512         * @param array    $actions An array of action links.
     513         * @param WP_Theme $theme   The current WP_Theme object.
     514         * @param string   $context Status of the theme.
     515         */
     516        $actions = apply_filters( "theme_action_links_{$stylesheet}", $actions, $theme, $context );
     517
     518        echo $this->row_actions( $actions, true );
     519    }
     520
     521    /**
     522     * Handles the description column output.
     523     *
     524     * @since 4.3.0
     525     * @access public
     526     *
     527     * @global string $status
     528     * @global array  $totals
     529     *
     530     * @param WP_Theme $theme The current WP_Theme object.
     531     */
     532    public function column_description( $theme ) {
     533        global $status, $totals;
     534        if ( $theme->errors() ) {
     535            $pre = $status === 'broken' ? __( 'Broken Theme:' ) . ' ' : '';
     536            echo '<p><strong class="error-message">' . $pre . $theme->errors()->get_error_message() . '</strong></p>';
     537        }
     538
     539        if ( $this->is_site_themes ) {
     540            $allowed = $theme->is_allowed( 'site', $this->site_id );
     541        } else {
     542            $allowed = $theme->is_allowed( 'network' );
     543        }
     544
     545        $class = ! $allowed ? 'inactive' : 'active';
     546        if ( ! empty( $totals['upgrade'] ) && ! empty( $theme->update ) )
     547            $class .= ' update';
     548
     549        echo "<div class='theme-description'><p>" . $theme->display( 'Description' ) . "</p></div>
     550            <div class='$class second theme-version-author-uri'>";
     551
     552        $stylesheet = $theme->get_stylesheet();
     553        $theme_meta = array();
     554
     555        if ( $theme->get('Version') ) {
     556            $theme_meta[] = sprintf( __( 'Version %s' ), $theme->display('Version') );
     557        }
     558        $theme_meta[] = sprintf( __( 'By %s' ), $theme->display('Author') );
     559
     560        if ( $theme->get('ThemeURI') ) {
     561            /* translators: %s: theme name */
     562            $aria_label = sprintf( __( 'Visit %s homepage' ), $theme->display( 'Name' ) );
     563
     564            $theme_meta[] = sprintf( '<a href="%s" aria-label="%s">%s</a>',
     565                $theme->display( 'ThemeURI' ),
     566                esc_attr( $aria_label ),
     567                __( 'Visit Theme Site' )
     568            );
     569        }
     570        /**
     571         * Filters the array of row meta for each theme in the Multisite themes
     572         * list table.
     573         *
     574         * @since 3.1.0
     575         *
     576         * @param array    $theme_meta An array of the theme's metadata,
     577         *                             including the version, author, and
     578         *                             theme URI.
     579         * @param string   $stylesheet Directory name of the theme.
     580         * @param WP_Theme $theme      WP_Theme object.
     581         * @param string   $status     Status of the theme.
     582         */
     583        $theme_meta = apply_filters( 'theme_row_meta', $theme_meta, $stylesheet, $theme, $status );
     584        echo implode( ' | ', $theme_meta );
     585
     586        echo '</div>';
     587    }
     588
     589    /**
     590     * Handles default column output.
     591     *
     592     * @since 4.3.0
     593     * @access public
     594     *
     595     * @param WP_Theme $theme       The current WP_Theme object.
     596     * @param string   $column_name The current column name.
     597     */
     598    public function column_default( $theme, $column_name ) {
     599        $stylesheet = $theme->get_stylesheet();
     600
     601        /**
     602         * Fires inside each custom column of the Multisite themes list table.
     603         *
     604         * @since 3.1.0
     605         *
     606         * @param string   $column_name Name of the column.
     607         * @param string   $stylesheet  Directory name of the theme.
     608         * @param WP_Theme $theme       Current WP_Theme object.
     609         */
     610        do_action( 'manage_themes_custom_column', $column_name, $stylesheet, $theme );
     611    }
     612
     613    /**
     614     * Handles the output for a single table row.
     615     *
     616     * @since 4.3.0
     617     * @access public
     618     *
     619     * @param WP_Theme $item The current WP_Theme object.
     620     */
     621    public function single_row_columns( $item ) {
     622        list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
     623
     624        foreach ( $columns as $column_name => $column_display_name ) {
     625            $extra_classes = '';
     626            if ( in_array( $column_name, $hidden ) ) {
     627                $extra_classes .= ' hidden';
     628            }
     629
     630            switch ( $column_name ) {
     631                case 'cb':
     632                    echo '<th scope="row" class="check-column">';
     633
     634                    $this->column_cb( $item );
     635
     636                    echo '</th>';
     637                    break;
     638
     639                case 'name':
     640                    echo "<td class='theme-title column-primary{$extra_classes}'><strong>" . $item->display('Name') . "</strong>";
     641
     642                    $this->column_name( $item );
     643
     644                    echo "</td>";
     645                    break;
     646
     647                case 'description':
     648                    echo "<td class='column-description desc{$extra_classes}'>";
     649
     650                    $this->column_description( $item );
     651
     652                    echo '</td>';
     653                    break;
     654
     655                default:
     656                    echo "<td class='$column_name column-$column_name{$extra_classes}'>";
     657
     658                    $this->column_default( $item, $column_name );
     659
     660                    echo "</td>";
     661                    break;
     662            }
     663        }
     664    }
     665
     666    /**
     667     * @global string $status
     668     * @global array  $totals
     669     *
     670     * @param WP_Theme $theme
     671     */
     672    public function single_row( $theme ) {
     673        global $status, $totals;
     674
     675        if ( $this->is_site_themes ) {
     676            $allowed = $theme->is_allowed( 'site', $this->site_id );
     677        } else {
     678            $allowed = $theme->is_allowed( 'network' );
     679        }
     680
     681        $stylesheet = $theme->get_stylesheet();
     682
     683        $class = ! $allowed ? 'inactive' : 'active';
     684        if ( ! empty( $totals['upgrade'] ) && ! empty( $theme->update ) ) {
     685            $class .= ' update';
     686        }
     687
     688        printf( '<tr class="%s" data-slug="%s">',
     689            esc_attr( $class ),
     690            esc_attr( $stylesheet )
     691        );
     692
     693        $this->single_row_columns( $theme );
     694
     695        echo "</tr>";
     696
     697        if ( $this->is_site_themes )
     698            remove_action( "after_theme_row_$stylesheet", 'wp_theme_update_row' );
     699
     700        /**
     701         * Fires after each row in the Multisite themes list table.
     702         *
     703         * @since 3.1.0
     704         *
     705         * @param string   $stylesheet Directory name of the theme.
     706         * @param WP_Theme $theme      Current WP_Theme object.
     707         * @param string   $status     Status of the theme.
     708         */
     709        do_action( 'after_theme_row', $stylesheet, $theme, $status );
     710
     711        /**
     712         * Fires after each specific row in the Multisite themes list table.
     713         *
     714         * The dynamic portion of the hook name, `$stylesheet`, refers to the
     715         * directory name of the theme, most often synonymous with the template
     716         * name of the theme.
     717         *
     718         * @since 3.5.0
     719         *
     720         * @param string   $stylesheet Directory name of the theme.
     721         * @param WP_Theme $theme      Current WP_Theme object.
     722         * @param string   $status     Status of the theme.
     723         */
     724        do_action( "after_theme_row_{$stylesheet}", $stylesheet, $theme, $status );
     725    }
    732726}
  • src/wp-admin/includes/class-wp-plugin-install-list-table.php

    diff --git a/src/wp-admin/includes/class-wp-plugin-install-list-table.php b/src/wp-admin/includes/class-wp-plugin-install-list-table.php
    index cd718360cb..fd119cc6da 100644
    a b  
    1717 */
    1818class WP_Plugin_Install_List_Table extends WP_List_Table {
    1919
    20         public $order = 'ASC';
    21         public $orderby = null;
    22         public $groups = array();
    23 
    24         private $error;
    25 
    26         /**
    27          *
    28          * @return bool
    29          */
    30         public function ajax_user_can() {
    31                 return current_user_can('install_plugins');
    32         }
    33 
    34         /**
    35          * Return a list of slugs of installed plugins, if known.
    36          *
    37          * Uses the transient data from the updates API to determine the slugs of
    38          * known installed plugins. This might be better elsewhere, perhaps even
    39          * within get_plugins().
    40          *
    41          * @since 4.0.0
    42          * @access protected
    43          *
    44          * @return array
    45          */
    46         protected function get_installed_plugin_slugs() {
    47                 $slugs = array();
    48 
    49                 $plugin_info = get_site_transient( 'update_plugins' );
    50                 if ( isset( $plugin_info->no_update ) ) {
    51                         foreach ( $plugin_info->no_update as $plugin ) {
    52                                 $slugs[] = $plugin->slug;
    53                         }
    54                 }
    55 
    56                 if ( isset( $plugin_info->response ) ) {
    57                         foreach ( $plugin_info->response as $plugin ) {
    58                                 $slugs[] = $plugin->slug;
    59                         }
    60                 }
    61 
    62                 return $slugs;
    63         }
    64 
    65         /**
    66          *
    67          * @global array  $tabs
    68          * @global string $tab
    69          * @global int    $paged
    70          * @global string $type
    71          * @global string $term
    72          */
    73         public function prepare_items() {
    74                 include( ABSPATH . 'wp-admin/includes/plugin-install.php' );
    75 
    76                 global $tabs, $tab, $paged, $type, $term;
    77 
    78                 wp_reset_vars( array( 'tab' ) );
    79 
    80                 $paged = $this->get_pagenum();
    81 
    82                 $per_page = 30;
    83 
    84                 // These are the tabs which are shown on the page
    85                 $tabs = array();
    86 
    87                 if ( 'search' === $tab ) {
    88                         $tabs['search'] = __( 'Search Results' );
    89                 }
    90                 if ( $tab === 'beta' || false !== strpos( get_bloginfo( 'version' ), '-' ) ) {
    91                         $tabs['beta'] = _x( 'Beta Testing', 'Plugin Installer' );
    92                 }
    93                 $tabs['featured']    = _x( 'Featured', 'Plugin Installer' );
    94                 $tabs['popular']     = _x( 'Popular', 'Plugin Installer' );
    95                 $tabs['recommended'] = _x( 'Recommended', 'Plugin Installer' );
    96                 $tabs['favorites']   = _x( 'Favorites', 'Plugin Installer' );
    97                 if ( current_user_can( 'upload_plugins' ) ) {
    98                         // No longer a real tab. Here for filter compatibility.
    99                         // Gets skipped in get_views().
    100                         $tabs['upload'] = __( 'Upload Plugin' );
    101                 }
    102 
    103                 $nonmenu_tabs = array( 'plugin-information' ); // Valid actions to perform which do not have a Menu item.
    104 
    105                 /**
    106                  * Filters the tabs shown on the Plugin Install screen.
    107                  *
    108                  * @since 2.7.0
    109                  *
    110                  * @param array $tabs The tabs shown on the Plugin Install screen. Defaults include 'featured', 'popular',
    111                  *                    'recommended', 'favorites', and 'upload'.
    112                  */
    113                 $tabs = apply_filters( 'install_plugins_tabs', $tabs );
    114 
    115                 /**
    116                  * Filters tabs not associated with a menu item on the Plugin Install screen.
    117                  *
    118                  * @since 2.7.0
    119                  *
    120                  * @param array $nonmenu_tabs The tabs that don't have a Menu item on the Plugin Install screen.
    121                  */
    122                 $nonmenu_tabs = apply_filters( 'install_plugins_nonmenu_tabs', $nonmenu_tabs );
    123 
    124                 // If a non-valid menu tab has been selected, And it's not a non-menu action.
    125                 if ( empty( $tab ) || ( !isset( $tabs[ $tab ] ) && !in_array( $tab, (array) $nonmenu_tabs ) ) )
    126                         $tab = key( $tabs );
    127 
    128                 $args = array(
    129                         'page' => $paged,
    130                         'per_page' => $per_page,
    131                         'fields' => array(
    132                                 'last_updated' => true,
    133                                 'icons' => true,
    134                                 'active_installs' => true
    135                         ),
    136                         // Send the locale and installed plugin slugs to the API so it can provide context-sensitive results.
    137                         'locale' => get_user_locale(),
    138                         'installed_plugins' => $this->get_installed_plugin_slugs(),
    139                 );
    140 
    141                 switch ( $tab ) {
    142                         case 'search':
    143                                 $type = isset( $_REQUEST['type'] ) ? wp_unslash( $_REQUEST['type'] ) : 'term';
    144                                 $term = isset( $_REQUEST['s'] ) ? wp_unslash( $_REQUEST['s'] ) : '';
    145 
    146                                 switch ( $type ) {
    147                                         case 'tag':
    148                                                 $args['tag'] = sanitize_title_with_dashes( $term );
    149                                                 break;
    150                                         case 'term':
    151                                                 $args['search'] = $term;
    152                                                 break;
    153                                         case 'author':
    154                                                 $args['author'] = $term;
    155                                                 break;
    156                                 }
    157 
    158                                 break;
    159 
    160                         case 'featured':
    161                                 $args['fields']['group'] = true;
    162                                 $this->orderby = 'group';
    163                                 // No break!
    164                         case 'popular':
    165                         case 'new':
    166                         case 'beta':
    167                         case 'recommended':
    168                                 $args['browse'] = $tab;
    169                                 break;
    170 
    171                         case 'favorites':
    172                                 $action = 'save_wporg_username_' . get_current_user_id();
    173                                 if ( isset( $_GET['_wpnonce'] ) && wp_verify_nonce( wp_unslash( $_GET['_wpnonce'] ), $action ) ) {
    174                                         $user = isset( $_GET['user'] ) ? wp_unslash( $_GET['user'] ) : get_user_option( 'wporg_favorites' );
    175                                         update_user_meta( get_current_user_id(), 'wporg_favorites', $user );
    176                                 } else {
    177                                         $user = get_user_option( 'wporg_favorites' );
    178                                 }
    179                                 if ( $user )
    180                                         $args['user'] = $user;
    181                                 else
    182                                         $args = false;
    183 
    184                                 add_action( 'install_plugins_favorites', 'install_plugins_favorites_form', 9, 0 );
    185                                 break;
    186 
    187                         default:
    188                                 $args = false;
    189                                 break;
    190                 }
    191 
    192                 /**
    193                  * Filters API request arguments for each Plugin Install screen tab.
    194                  *
    195                  * The dynamic portion of the hook name, `$tab`, refers to the plugin install tabs.
    196                  * Default tabs include 'featured', 'popular', 'recommended', 'favorites', and 'upload'.
    197                  *
    198                  * @since 3.7.0
    199                  *
    200                  * @param array|bool $args Plugin Install API arguments.
    201                  */
    202                 $args = apply_filters( "install_plugins_table_api_args_{$tab}", $args );
    203 
    204                 if ( !$args )
    205                         return;
    206 
    207                 $api = plugins_api( 'query_plugins', $args );
    208 
    209                 if ( is_wp_error( $api ) ) {
    210                         $this->error = $api;
    211                         return;
    212                 }
    213 
    214                 $this->items = $api->plugins;
    215 
    216                 if ( $this->orderby ) {
    217                         uasort( $this->items, array( $this, 'order_callback' ) );
    218                 }
    219 
    220                 $this->set_pagination_args( array(
    221                         'total_items' => $api->info['results'],
    222                         'per_page' => $args['per_page'],
    223                 ) );
    224 
    225                 if ( isset( $api->info['groups'] ) ) {
    226                         $this->groups = $api->info['groups'];
    227                 }
    228         }
    229 
    230         /**
    231          * @access public
    232          */
    233         public function no_items() {
    234                 if ( isset( $this->error ) ) {
    235                         $message = $this->error->get_error_message() . '<p class="hide-if-no-js"><a href="#" class="button" onclick="document.location.reload(); return false;">' . __( 'Try again' ) . '</a></p>';
    236                 } else {
    237                         $message = __( 'No plugins match your request.' );
    238                 }
    239                 echo '<div class="no-plugin-results">' . $message . '</div>';
    240         }
    241 
    242         /**
    243          *
    244          * @global array $tabs
    245          * @global string $tab
    246          *
    247          * @return array
    248          */
    249         protected function get_views() {
    250                 global $tabs, $tab;
    251 
    252                 $display_tabs = array();
    253                 foreach ( (array) $tabs as $action => $text ) {
    254                         $class = ( $action === $tab ) ? ' current' : '';
    255                         $href = self_admin_url('plugin-install.php?tab=' . $action);
    256                         $display_tabs['plugin-install-'.$action] = "<a href='$href' class='$class'>$text</a>";
    257                 }
    258                 // No longer a real tab.
    259                 unset( $display_tabs['plugin-install-upload'] );
    260 
    261                 return $display_tabs;
    262         }
    263 
    264         /**
    265          * Override parent views so we can use the filter bar display.
    266          */
    267         public function views() {
    268                 $views = $this->get_views();
    269 
    270                 /** This filter is documented in wp-admin/inclues/class-wp-list-table.php */
    271                 $views = apply_filters( "views_{$this->screen->id}", $views );
    272 
    273                 $this->screen->render_screen_reader_content( 'heading_views' );
     20    public $order = 'ASC';
     21    public $orderby = null;
     22    public $groups = array();
     23
     24    private $error;
     25
     26    /**
     27     *
     28     * @return bool
     29     */
     30    public function ajax_user_can() {
     31        return current_user_can('install_plugins');
     32    }
     33
     34    /**
     35     * Return a list of slugs of installed plugins, if known.
     36     *
     37     * Uses the transient data from the updates API to determine the slugs of
     38     * known installed plugins. This might be better elsewhere, perhaps even
     39     * within get_plugins().
     40     *
     41     * @since 4.0.0
     42     * @access protected
     43     *
     44     * @return array
     45     */
     46    protected function get_installed_plugin_slugs() {
     47        $slugs = array();
     48
     49        $plugin_info = get_site_transient( 'update_plugins' );
     50        if ( isset( $plugin_info->no_update ) ) {
     51            foreach ( $plugin_info->no_update as $plugin ) {
     52                $slugs[] = $plugin->slug;
     53            }
     54        }
     55
     56        if ( isset( $plugin_info->response ) ) {
     57            foreach ( $plugin_info->response as $plugin ) {
     58                $slugs[] = $plugin->slug;
     59            }
     60        }
     61
     62        return $slugs;
     63    }
     64
     65    public function prepare_items() {
     66        include( ABSPATH . 'wp-admin/includes/plugin-install.php' );
     67
     68        $tab = wp_assign_request_var('tab');
     69        $type = wp_assign_request_var('type');
     70        $term = wp_assign_request_var('term');
     71
     72        $paged = $this->get_pagenum();
     73
     74        $per_page = 30;
     75
     76        // These are the tabs which are shown on the page
     77        $tabs = array();
     78
     79        if ( 'search' === $tab ) {
     80            $tabs['search'] = __( 'Search Results' );
     81        }
     82        if ( $tab === 'beta' || false !== strpos( get_bloginfo( 'version' ), '-' ) ) {
     83            $tabs['beta'] = _x( 'Beta Testing', 'Plugin Installer' );
     84        }
     85        $tabs['featured']    = _x( 'Featured', 'Plugin Installer' );
     86        $tabs['popular']     = _x( 'Popular', 'Plugin Installer' );
     87        $tabs['recommended'] = _x( 'Recommended', 'Plugin Installer' );
     88        $tabs['favorites']   = _x( 'Favorites', 'Plugin Installer' );
     89        if ( current_user_can( 'upload_plugins' ) ) {
     90            // No longer a real tab. Here for filter compatibility.
     91            // Gets skipped in get_views().
     92            $tabs['upload'] = __( 'Upload Plugin' );
     93        }
     94
     95        $nonmenu_tabs = array( 'plugin-information' ); // Valid actions to perform which do not have a Menu item.
     96
     97        /**
     98         * Filters the tabs shown on the Plugin Install screen.
     99         *
     100         * @since 2.7.0
     101         *
     102         * @param array $tabs The tabs shown on the Plugin Install screen. Defaults include 'featured', 'popular',
     103         *                    'recommended', 'favorites', and 'upload'.
     104         */
     105        $tabs = apply_filters( 'install_plugins_tabs', $tabs );
     106
     107        /**
     108         * Filters tabs not associated with a menu item on the Plugin Install screen.
     109         *
     110         * @since 2.7.0
     111         *
     112         * @param array $nonmenu_tabs The tabs that don't have a Menu item on the Plugin Install screen.
     113         */
     114        $nonmenu_tabs = apply_filters( 'install_plugins_nonmenu_tabs', $nonmenu_tabs );
     115
     116        // If a non-valid menu tab has been selected, And it's not a non-menu action.
     117        if ( empty( $tab ) || ( !isset( $tabs[ $tab ] ) && !in_array( $tab, (array) $nonmenu_tabs ) ) )
     118            $tab = key( $tabs );
     119
     120        $args = array(
     121            'page' => $paged,
     122            'per_page' => $per_page,
     123            'fields' => array(
     124                'last_updated' => true,
     125                'icons' => true,
     126                'active_installs' => true
     127            ),
     128            // Send the locale and installed plugin slugs to the API so it can provide context-sensitive results.
     129            'locale' => get_user_locale(),
     130            'installed_plugins' => $this->get_installed_plugin_slugs(),
     131        );
     132
     133        switch ( $tab ) {
     134            case 'search':
     135                $type = isset( $_REQUEST['type'] ) ? wp_unslash( $_REQUEST['type'] ) : 'term';
     136                $term = isset( $_REQUEST['s'] ) ? wp_unslash( $_REQUEST['s'] ) : '';
     137
     138                switch ( $type ) {
     139                    case 'tag':
     140                        $args['tag'] = sanitize_title_with_dashes( $term );
     141                        break;
     142                    case 'term':
     143                        $args['search'] = $term;
     144                        break;
     145                    case 'author':
     146                        $args['author'] = $term;
     147                        break;
     148                }
     149
     150                break;
     151
     152            case 'featured':
     153                $args['fields']['group'] = true;
     154                $this->orderby = 'group';
     155                // No break!
     156            case 'popular':
     157            case 'new':
     158            case 'beta':
     159            case 'recommended':
     160                $args['browse'] = $tab;
     161                break;
     162
     163            case 'favorites':
     164                $action = 'save_wporg_username_' . get_current_user_id();
     165                if ( isset( $_GET['_wpnonce'] ) && wp_verify_nonce( wp_unslash( $_GET['_wpnonce'] ), $action ) ) {
     166                    $user = isset( $_GET['user'] ) ? wp_unslash( $_GET['user'] ) : get_user_option( 'wporg_favorites' );
     167                    update_user_meta( get_current_user_id(), 'wporg_favorites', $user );
     168                } else {
     169                    $user = get_user_option( 'wporg_favorites' );
     170                }
     171                if ( $user )
     172                    $args['user'] = $user;
     173                else
     174                    $args = false;
     175
     176                add_action( 'install_plugins_favorites', 'install_plugins_favorites_form', 9, 0 );
     177                break;
     178
     179            default:
     180                $args = false;
     181                break;
     182        }
     183
     184        /**
     185         * Filters API request arguments for each Plugin Install screen tab.
     186         *
     187         * The dynamic portion of the hook name, `$tab`, refers to the plugin install tabs.
     188         * Default tabs include 'featured', 'popular', 'recommended', 'favorites', and 'upload'.
     189         *
     190         * @since 3.7.0
     191         *
     192         * @param array|bool $args Plugin Install API arguments.
     193         */
     194        $args = apply_filters( "install_plugins_table_api_args_{$tab}", $args );
     195
     196        if ( !$args )
     197            return;
     198
     199        $api = plugins_api( 'query_plugins', $args );
     200
     201        if ( is_wp_error( $api ) ) {
     202            $this->error = $api;
     203            return;
     204        }
     205
     206        $this->items = $api->plugins;
     207
     208        if ( $this->orderby ) {
     209            uasort( $this->items, array( $this, 'order_callback' ) );
     210        }
     211
     212        $this->set_pagination_args( array(
     213            'total_items' => $api->info['results'],
     214            'per_page' => $args['per_page'],
     215        ) );
     216
     217        if ( isset( $api->info['groups'] ) ) {
     218            $this->groups = $api->info['groups'];
     219        }
     220    }
     221
     222    /**
     223     * @access public
     224     */
     225    public function no_items() {
     226        if ( isset( $this->error ) ) {
     227            $message = $this->error->get_error_message() . '<p class="hide-if-no-js"><a href="#" class="button" onclick="document.location.reload(); return false;">' . __( 'Try again' ) . '</a></p>';
     228        } else {
     229            $message = __( 'No plugins match your request.' );
     230        }
     231        echo '<div class="no-plugin-results">' . $message . '</div>';
     232    }
     233
     234    /**
     235     *
     236     * @global array $tabs
     237     * @global string $tab
     238     *
     239     * @return array
     240     */
     241    protected function get_views() {
     242        global $tabs, $tab;
     243
     244        $display_tabs = array();
     245        foreach ( (array) $tabs as $action => $text ) {
     246            $class = ( $action === $tab ) ? ' current' : '';
     247            $href = self_admin_url('plugin-install.php?tab=' . $action);
     248            $display_tabs['plugin-install-'.$action] = "<a href='$href' class='$class'>$text</a>";
     249        }
     250        // No longer a real tab.
     251        unset( $display_tabs['plugin-install-upload'] );
     252
     253        return $display_tabs;
     254    }
     255
     256    /**
     257     * Override parent views so we can use the filter bar display.
     258     */
     259    public function views() {
     260        $views = $this->get_views();
     261
     262        /** This filter is documented in wp-admin/inclues/class-wp-list-table.php */
     263        $views = apply_filters( "views_{$this->screen->id}", $views );
     264
     265        $this->screen->render_screen_reader_content( 'heading_views' );
    274266?>
    275267<div class="wp-filter">
    276         <ul class="filter-links">
    277                 <?php
    278                 if ( ! empty( $views ) ) {
    279                         foreach ( $views as $class => $view ) {
    280                                 $views[ $class ] = "\t<li class='$class'>$view";
    281                         }
    282                         echo implode( " </li>\n", $views ) . "</li>\n";
    283                 }
    284                 ?>
    285         </ul>
    286 
    287         <?php install_search_form(); ?>
     268    <ul class="filter-links">
     269        <?php
     270        if ( ! empty( $views ) ) {
     271            foreach ( $views as $class => $view ) {
     272                $views[ $class ] = "\t<li class='$class'>$view";
     273            }
     274            echo implode( " </li>\n", $views ) . "</li>\n";
     275        }
     276        ?>
     277    </ul>
     278
     279    <?php install_search_form(); ?>
    288280</div>
    289281<?php
    290         }
     282    }
    291283
    292         /**
    293         * Override the parent display() so we can provide a different container.
    294         */
    295         public function display() {
    296                 $singular = $this->_args['singular'];
     284    /**
     285    * Override the parent display() so we can provide a different container.
     286    */
     287    public function display() {
     288        $singular = $this->_args['singular'];
    297289
    298                 $data_attr = '';
     290        $data_attr = '';
    299291
    300                 if ( $singular ) {
    301                         $data_attr = " data-wp-lists='list:$singular'";
    302                 }
     292        if ( $singular ) {
     293            $data_attr = " data-wp-lists='list:$singular'";
     294        }
    303295
    304                 $this->display_tablenav( 'top' );
     296        $this->display_tablenav( 'top' );
    305297
    306298?>
    307299<div class="wp-list-table <?php echo implode( ' ', $this->get_table_classes() ); ?>">
    308300<?php
    309         $this->screen->render_screen_reader_content( 'heading_list' );
     301    $this->screen->render_screen_reader_content( 'heading_list' );
    310302?>
    311         <div id="the-list"<?php echo $data_attr; ?>>
    312                 <?php $this->display_rows_or_placeholder(); ?>
    313         </div>
     303    <div id="the-list"<?php echo $data_attr; ?>>
     304        <?php $this->display_rows_or_placeholder(); ?>
     305    </div>
    314306</div>
    315307<?php
    316                 $this->display_tablenav( 'bottom' );
    317         }
    318 
    319         /**
    320         * @global string $tab
    321         *
    322         * @param string $which
    323         */
    324         protected function display_tablenav( $which ) {
    325                 if ( $GLOBALS['tab'] === 'featured' ) {
    326                         return;
    327                 }
    328 
    329                 if ( 'top' === $which ) {
    330                         wp_referer_field();
    331                 ?>
    332                         <div class="tablenav top">
    333                                 <div class="alignleft actions">
    334                                         <?php
    335                                         /**
    336                                         * Fires before the Plugin Install table header pagination is displayed.
    337                                         *
    338                                         * @since 2.7.0
    339                                         */
    340                                         do_action( 'install_plugins_table_header' ); ?>
    341                                 </div>
    342                                 <?php $this->pagination( $which ); ?>
    343                                 <br class="clear" />
    344                         </div>
    345                 <?php } else { ?>
    346                         <div class="tablenav bottom">
    347                                 <?php $this->pagination( $which ); ?>
    348                                 <br class="clear" />
    349                         </div>
    350                 <?php
    351                 }
    352         }
    353 
    354         /**
    355         * @return array
    356         */
    357         protected function get_table_classes() {
    358                 return array( 'widefat', $this->_args['plural'] );
    359         }
    360 
    361         /**
    362         * @return array
    363         */
    364         public function get_columns() {
    365                 return array();
    366         }
    367 
    368         /**
    369         * @param object $plugin_a
    370         * @param object $plugin_b
    371         * @return int
    372         */
    373         private function order_callback( $plugin_a, $plugin_b ) {
    374                 $orderby = $this->orderby;
    375                 if ( ! isset( $plugin_a->$orderby, $plugin_b->$orderby ) ) {
    376                         return 0;
    377                 }
    378 
    379                 $a = $plugin_a->$orderby;
    380                 $b = $plugin_b->$orderby;
    381 
    382                 if ( $a == $b ) {
    383                         return 0;
    384                 }
    385 
    386                 if ( 'DESC' === $this->order ) {
    387                         return ( $a < $b ) ? 1 : -1;
    388                 } else {
    389                         return ( $a < $b ) ? -1 : 1;
    390                 }
    391         }
    392 
    393         public function display_rows() {
    394                 $plugins_allowedtags = array(
    395                         'a' => array( 'href' => array(),'title' => array(), 'target' => array() ),
    396                         'abbr' => array( 'title' => array() ),'acronym' => array( 'title' => array() ),
    397                         'code' => array(), 'pre' => array(), 'em' => array(),'strong' => array(),
    398                         'ul' => array(), 'ol' => array(), 'li' => array(), 'p' => array(), 'br' => array()
    399                 );
    400 
    401                 $plugins_group_titles = array(
    402                         'Performance' => _x( 'Performance', 'Plugin installer group title' ),
    403                         'Social'      => _x( 'Social',      'Plugin installer group title' ),
    404                         'Tools'       => _x( 'Tools',       'Plugin installer group title' ),
    405                 );
    406 
    407                 $group = null;
    408 
    409                 foreach ( (array) $this->items as $plugin ) {
    410                         if ( is_object( $plugin ) ) {
    411                                 $plugin = (array) $plugin;
    412                         }
    413 
    414                         // Display the group heading if there is one
    415                         if ( isset( $plugin['group'] ) && $plugin['group'] != $group ) {
    416                                 if ( isset( $this->groups[ $plugin['group'] ] ) ) {
    417                                         $group_name = $this->groups[ $plugin['group'] ];
    418                                         if ( isset( $plugins_group_titles[ $group_name ] ) ) {
    419                                                 $group_name = $plugins_group_titles[ $group_name ];
    420                                         }
    421                                 } else {
    422                                         $group_name = $plugin['group'];
    423                                 }
    424 
    425                                 // Starting a new group, close off the divs of the last one
    426                                 if ( ! empty( $group ) ) {
    427                                         echo '</div></div>';
    428                                 }
    429 
    430                                 echo '<div class="plugin-group"><h3>' . esc_html( $group_name ) . '</h3>';
    431                                 // needs an extra wrapping div for nth-child selectors to work
    432                                 echo '<div class="plugin-items">';
    433 
    434                                 $group = $plugin['group'];
    435                         }
    436                         $title = wp_kses( $plugin['name'], $plugins_allowedtags );
    437 
    438                         // Remove any HTML from the description.
    439                         $description = strip_tags( $plugin['short_description'] );
    440                         $version = wp_kses( $plugin['version'], $plugins_allowedtags );
    441 
    442                         $name = strip_tags( $title . ' ' . $version );
    443 
    444                         $author = wp_kses( $plugin['author'], $plugins_allowedtags );
    445                         if ( ! empty( $author ) ) {
    446                                 $author = ' <cite>' . sprintf( __( 'By %s' ), $author ) . '</cite>';
    447                         }
    448 
    449                         $action_links = array();
    450 
    451                         if ( current_user_can( 'install_plugins' ) || current_user_can( 'update_plugins' ) ) {
    452                                 $status = install_plugin_install_status( $plugin );
    453 
    454                                 switch ( $status['status'] ) {
    455                                         case 'install':
    456                                                 if ( $status['url'] ) {
    457                                                         /* translators: 1: Plugin name and version. */
    458                                                         $action_links[] = '<a class="install-now button" data-slug="' . esc_attr( $plugin['slug'] ) . '" href="' . esc_url( $status['url'] ) . '" aria-label="' . esc_attr( sprintf( __( 'Install %s now' ), $name ) ) . '" data-name="' . esc_attr( $name ) . '">' . __( 'Install Now' ) . '</a>';
    459                                                 }
    460                                                 break;
    461 
    462                                         case 'update_available':
    463                                                 if ( $status['url'] ) {
    464                                                         /* translators: 1: Plugin name and version */
    465                                                         $action_links[] = '<a class="update-now button aria-button-if-js" data-plugin="' . esc_attr( $status['file'] ) . '" data-slug="' . esc_attr( $plugin['slug'] ) . '" href="' . esc_url( $status['url'] ) . '" aria-label="' . esc_attr( sprintf( __( 'Update %s now' ), $name ) ) . '" data-name="' . esc_attr( $name ) . '">' . __( 'Update Now' ) . '</a>';
    466                                                 }
    467                                                 break;
    468 
    469                                         case 'latest_installed':
    470                                         case 'newer_installed':
    471                                                 if ( is_plugin_active( $status['file'] ) ) {
    472                                                         $action_links[] = '<button type="button" class="button button-disabled" disabled="disabled">' . _x( 'Active', 'plugin' ) . '</button>';
    473                                                 } elseif ( current_user_can( 'activate_plugins' ) ) {
    474                                                         $button_text  = __( 'Activate' );
    475                                                         /* translators: %s: Plugin name */
    476                                                         $button_label = _x( 'Activate %s', 'plugin' );
    477                                                         $activate_url = add_query_arg( array(
    478                                                                 '_wpnonce'    => wp_create_nonce( 'activate-plugin_' . $status['file'] ),
    479                                                                 'action'      => 'activate',
    480                                                                 'plugin'      => $status['file'],
    481                                                         ), network_admin_url( 'plugins.php' ) );
    482 
    483                                                         if ( is_network_admin() ) {
    484                                                                 $button_text  = __( 'Network Activate' );
    485                                                                 /* translators: %s: Plugin name */
    486                                                                 $button_label = _x( 'Network Activate %s', 'plugin' );
    487                                                                 $activate_url = add_query_arg( array( 'networkwide' => 1 ), $activate_url );
    488                                                         }
    489 
    490                                                         $action_links[] = sprintf(
    491                                                                 '<a href="%1$s" class="button activate-now" aria-label="%2$s">%3$s</a>',
    492                                                                 esc_url( $activate_url ),
    493                                                                 esc_attr( sprintf( $button_label, $plugin['name'] ) ),
    494                                                                 $button_text
    495                                                         );
    496                                                 } else {
    497                                                         $action_links[] = '<button type="button" class="button button-disabled" disabled="disabled">' . _x( 'Installed', 'plugin' ) . '</button>';
    498                                                 }
    499                                                 break;
    500                                 }
    501                         }
    502 
    503                         $details_link   = self_admin_url( 'plugin-install.php?tab=plugin-information&amp;plugin=' . $plugin['slug'] .
    504                                                                 '&amp;TB_iframe=true&amp;width=600&amp;height=550' );
    505 
    506                         /* translators: 1: Plugin name and version. */
    507                         $action_links[] = '<a href="' . esc_url( $details_link ) . '" class="thickbox open-plugin-details-modal" aria-label="' . esc_attr( sprintf( __( 'More information about %s' ), $name ) ) . '" data-title="' . esc_attr( $name ) . '">' . __( 'More Details' ) . '</a>';
    508 
    509                         if ( !empty( $plugin['icons']['svg'] ) ) {
    510                                 $plugin_icon_url = $plugin['icons']['svg'];
    511                         } elseif ( !empty( $plugin['icons']['2x'] ) ) {
    512                                 $plugin_icon_url = $plugin['icons']['2x'];
    513                         } elseif ( !empty( $plugin['icons']['1x'] ) ) {
    514                                 $plugin_icon_url = $plugin['icons']['1x'];
    515                         } else {
    516                                 $plugin_icon_url = $plugin['icons']['default'];
    517                         }
    518 
    519                         /**
    520                         * Filters the install action links for a plugin.
    521                         *
    522                         * @since 2.7.0
    523                         *
    524                         * @param array $action_links An array of plugin action hyperlinks. Defaults are links to Details and Install Now.
    525                         * @param array $plugin       The plugin currently being listed.
    526                         */
    527                         $action_links = apply_filters( 'plugin_install_action_links', $action_links, $plugin );
    528 
    529                         $last_updated_timestamp = strtotime( $plugin['last_updated'] );
    530                 ?>
    531                 <div class="plugin-card plugin-card-<?php echo sanitize_html_class( $plugin['slug'] ); ?>">
    532                         <div class="plugin-card-top">
    533                                 <div class="name column-name">
    534                                         <h3>
    535                                                 <a href="<?php echo esc_url( $details_link ); ?>" class="thickbox open-plugin-details-modal">
    536                                                 <?php echo $title; ?>
    537                                                 <img src="<?php echo esc_attr( $plugin_icon_url ) ?>" class="plugin-icon" alt="">
    538                                                 </a>
    539                                         </h3>
    540                                 </div>
    541                                 <div class="action-links">
    542                                         <?php
    543                                                 if ( $action_links ) {
    544                                                         echo '<ul class="plugin-action-buttons"><li>' . implode( '</li><li>', $action_links ) . '</li></ul>';
    545                                                 }
    546                                         ?>
    547                                 </div>
    548                                 <div class="desc column-description">
    549                                         <p><?php echo $description; ?></p>
    550                                         <p class="authors"><?php echo $author; ?></p>
    551                                 </div>
    552                         </div>
    553                         <div class="plugin-card-bottom">
    554                                 <div class="vers column-rating">
    555                                         <?php wp_star_rating( array( 'rating' => $plugin['rating'], 'type' => 'percent', 'number' => $plugin['num_ratings'] ) ); ?>
    556                                         <span class="num-ratings" aria-hidden="true">(<?php echo number_format_i18n( $plugin['num_ratings'] ); ?>)</span>
    557                                 </div>
    558                                 <div class="column-updated">
    559                                         <strong><?php _e( 'Last Updated:' ); ?></strong> <?php printf( __( '%s ago' ), human_time_diff( $last_updated_timestamp ) ); ?>
    560                                 </div>
    561                                 <div class="column-downloaded">
    562                                         <?php
    563                                         if ( $plugin['active_installs'] >= 1000000 ) {
    564                                                 $active_installs_text = _x( '1+ Million', 'Active plugin installs' );
    565                                         } elseif ( 0 == $plugin['active_installs'] ) {
    566                                                 $active_installs_text = _x( 'Less Than 10', 'Active plugin installs' );
    567                                         } else {
    568                                                 $active_installs_text = number_format_i18n( $plugin['active_installs'] ) . '+';
    569                                         }
    570                                         printf( __( '%s Active Installs' ), $active_installs_text );
    571                                         ?>
    572                                 </div>
    573                                 <div class="column-compatibility">
    574                                         <?php
    575                                         $wp_version = get_bloginfo( 'version' );
    576 
    577                                         if ( ! empty( $plugin['tested'] ) && version_compare( substr( $wp_version, 0, strlen( $plugin['tested'] ) ), $plugin['tested'], '>' ) ) {
    578                                                 echo '<span class="compatibility-untested">' . __( 'Untested with your version of WordPress' ) . '</span>';
    579                                         } elseif ( ! empty( $plugin['requires'] ) && version_compare( substr( $wp_version, 0, strlen( $plugin['requires'] ) ), $plugin['requires'], '<' ) ) {
    580                                                 echo '<span class="compatibility-incompatible">' . __( '<strong>Incompatible</strong> with your version of WordPress' ) . '</span>';
    581                                         } else {
    582                                                 echo '<span class="compatibility-compatible">' . __( '<strong>Compatible</strong> with your version of WordPress' ) . '</span>';
    583                                         }
    584                                         ?>
    585                                 </div>
    586                         </div>
    587                 </div>
    588                 <?php
    589                 }
    590 
    591                 // Close off the group divs of the last one
    592                 if ( ! empty( $group ) ) {
    593                         echo '</div></div>';
    594                 }
    595         }
     308        $this->display_tablenav( 'bottom' );
     309    }
     310
     311    /**
     312    * @global string $tab
     313    *
     314    * @param string $which
     315    */
     316    protected function display_tablenav( $which ) {
     317        if ( $GLOBALS['tab'] === 'featured' ) {
     318            return;
     319        }
     320
     321        if ( 'top' === $which ) {
     322            wp_referer_field();
     323        ?>
     324            <div class="tablenav top">
     325                <div class="alignleft actions">
     326                    <?php
     327                    /**
     328                    * Fires before the Plugin Install table header pagination is displayed.
     329                    *
     330                    * @since 2.7.0
     331                    */
     332                    do_action( 'install_plugins_table_header' ); ?>
     333                </div>
     334                <?php $this->pagination( $which ); ?>
     335                <br class="clear" />
     336            </div>
     337        <?php } else { ?>
     338            <div class="tablenav bottom">
     339                <?php $this->pagination( $which ); ?>
     340                <br class="clear" />
     341            </div>
     342        <?php
     343        }
     344    }
     345
     346    /**
     347    * @return array
     348    */
     349    protected function get_table_classes() {
     350        return array( 'widefat', $this->_args['plural'] );
     351    }
     352
     353    /**
     354    * @return array
     355    */
     356    public function get_columns() {
     357        return array();
     358    }
     359
     360    /**
     361    * @param object $plugin_a
     362    * @param object $plugin_b
     363    * @return int
     364    */
     365    private function order_callback( $plugin_a, $plugin_b ) {
     366        $orderby = $this->orderby;
     367        if ( ! isset( $plugin_a->$orderby, $plugin_b->$orderby ) ) {
     368            return 0;
     369        }
     370
     371        $a = $plugin_a->$orderby;
     372        $b = $plugin_b->$orderby;
     373
     374        if ( $a == $b ) {
     375            return 0;
     376        }
     377
     378        if ( 'DESC' === $this->order ) {
     379            return ( $a < $b ) ? 1 : -1;
     380        } else {
     381            return ( $a < $b ) ? -1 : 1;
     382        }
     383    }
     384
     385    public function display_rows() {
     386        $plugins_allowedtags = array(
     387            'a' => array( 'href' => array(),'title' => array(), 'target' => array() ),
     388            'abbr' => array( 'title' => array() ),'acronym' => array( 'title' => array() ),
     389            'code' => array(), 'pre' => array(), 'em' => array(),'strong' => array(),
     390            'ul' => array(), 'ol' => array(), 'li' => array(), 'p' => array(), 'br' => array()
     391        );
     392
     393        $plugins_group_titles = array(
     394            'Performance' => _x( 'Performance', 'Plugin installer group title' ),
     395            'Social'      => _x( 'Social',      'Plugin installer group title' ),
     396            'Tools'       => _x( 'Tools',       'Plugin installer group title' ),
     397        );
     398
     399        $group = null;
     400
     401        foreach ( (array) $this->items as $plugin ) {
     402            if ( is_object( $plugin ) ) {
     403                $plugin = (array) $plugin;
     404            }
     405
     406            // Display the group heading if there is one
     407            if ( isset( $plugin['group'] ) && $plugin['group'] != $group ) {
     408                if ( isset( $this->groups[ $plugin['group'] ] ) ) {
     409                    $group_name = $this->groups[ $plugin['group'] ];
     410                    if ( isset( $plugins_group_titles[ $group_name ] ) ) {
     411                        $group_name = $plugins_group_titles[ $group_name ];
     412                    }
     413                } else {
     414                    $group_name = $plugin['group'];
     415                }
     416
     417                // Starting a new group, close off the divs of the last one
     418                if ( ! empty( $group ) ) {
     419                    echo '</div></div>';
     420                }
     421
     422                echo '<div class="plugin-group"><h3>' . esc_html( $group_name ) . '</h3>';
     423                // needs an extra wrapping div for nth-child selectors to work
     424                echo '<div class="plugin-items">';
     425
     426                $group = $plugin['group'];
     427            }
     428            $title = wp_kses( $plugin['name'], $plugins_allowedtags );
     429
     430            // Remove any HTML from the description.
     431            $description = strip_tags( $plugin['short_description'] );
     432            $version = wp_kses( $plugin['version'], $plugins_allowedtags );
     433
     434            $name = strip_tags( $title . ' ' . $version );
     435
     436            $author = wp_kses( $plugin['author'], $plugins_allowedtags );
     437            if ( ! empty( $author ) ) {
     438                $author = ' <cite>' . sprintf( __( 'By %s' ), $author ) . '</cite>';
     439            }
     440
     441            $action_links = array();
     442
     443            if ( current_user_can( 'install_plugins' ) || current_user_can( 'update_plugins' ) ) {
     444                $status = install_plugin_install_status( $plugin );
     445
     446                switch ( $status['status'] ) {
     447                    case 'install':
     448                        if ( $status['url'] ) {
     449                            /* translators: 1: Plugin name and version. */
     450                            $action_links[] = '<a class="install-now button" data-slug="' . esc_attr( $plugin['slug'] ) . '" href="' . esc_url( $status['url'] ) . '" aria-label="' . esc_attr( sprintf( __( 'Install %s now' ), $name ) ) . '" data-name="' . esc_attr( $name ) . '">' . __( 'Install Now' ) . '</a>';
     451                        }
     452                        break;
     453
     454                    case 'update_available':
     455                        if ( $status['url'] ) {
     456                            /* translators: 1: Plugin name and version */
     457                            $action_links[] = '<a class="update-now button aria-button-if-js" data-plugin="' . esc_attr( $status['file'] ) . '" data-slug="' . esc_attr( $plugin['slug'] ) . '" href="' . esc_url( $status['url'] ) . '" aria-label="' . esc_attr( sprintf( __( 'Update %s now' ), $name ) ) . '" data-name="' . esc_attr( $name ) . '">' . __( 'Update Now' ) . '</a>';
     458                        }
     459                        break;
     460
     461                    case 'latest_installed':
     462                    case 'newer_installed':
     463                        if ( is_plugin_active( $status['file'] ) ) {
     464                            $action_links[] = '<button type="button" class="button button-disabled" disabled="disabled">' . _x( 'Active', 'plugin' ) . '</button>';
     465                        } elseif ( current_user_can( 'activate_plugins' ) ) {
     466                            $button_text  = __( 'Activate' );
     467                            /* translators: %s: Plugin name */
     468                            $button_label = _x( 'Activate %s', 'plugin' );
     469                            $activate_url = add_query_arg( array(
     470                                '_wpnonce'    => wp_create_nonce( 'activate-plugin_' . $status['file'] ),
     471                                'action'      => 'activate',
     472                                'plugin'      => $status['file'],
     473                            ), network_admin_url( 'plugins.php' ) );
     474
     475                            if ( is_network_admin() ) {
     476                                $button_text  = __( 'Network Activate' );
     477                                /* translators: %s: Plugin name */
     478                                $button_label = _x( 'Network Activate %s', 'plugin' );
     479                                $activate_url = add_query_arg( array( 'networkwide' => 1 ), $activate_url );
     480                            }
     481
     482                            $action_links[] = sprintf(
     483                                '<a href="%1$s" class="button activate-now" aria-label="%2$s">%3$s</a>',
     484                                esc_url( $activate_url ),
     485                                esc_attr( sprintf( $button_label, $plugin['name'] ) ),
     486                                $button_text
     487                            );
     488                        } else {
     489                            $action_links[] = '<button type="button" class="button button-disabled" disabled="disabled">' . _x( 'Installed', 'plugin' ) . '</button>';
     490                        }
     491                        break;
     492                }
     493            }
     494
     495            $details_link   = self_admin_url( 'plugin-install.php?tab=plugin-information&amp;plugin=' . $plugin['slug'] .
     496                                '&amp;TB_iframe=true&amp;width=600&amp;height=550' );
     497
     498            /* translators: 1: Plugin name and version. */
     499            $action_links[] = '<a href="' . esc_url( $details_link ) . '" class="thickbox open-plugin-details-modal" aria-label="' . esc_attr( sprintf( __( 'More information about %s' ), $name ) ) . '" data-title="' . esc_attr( $name ) . '">' . __( 'More Details' ) . '</a>';
     500
     501            if ( !empty( $plugin['icons']['svg'] ) ) {
     502                $plugin_icon_url = $plugin['icons']['svg'];
     503            } elseif ( !empty( $plugin['icons']['2x'] ) ) {
     504                $plugin_icon_url = $plugin['icons']['2x'];
     505            } elseif ( !empty( $plugin['icons']['1x'] ) ) {
     506                $plugin_icon_url = $plugin['icons']['1x'];
     507            } else {
     508                $plugin_icon_url = $plugin['icons']['default'];
     509            }
     510
     511            /**
     512            * Filters the install action links for a plugin.
     513            *
     514            * @since 2.7.0
     515            *
     516            * @param array $action_links An array of plugin action hyperlinks. Defaults are links to Details and Install Now.
     517            * @param array $plugin       The plugin currently being listed.
     518            */
     519            $action_links = apply_filters( 'plugin_install_action_links', $action_links, $plugin );
     520
     521            $last_updated_timestamp = strtotime( $plugin['last_updated'] );
     522        ?>
     523        <div class="plugin-card plugin-card-<?php echo sanitize_html_class( $plugin['slug'] ); ?>">
     524            <div class="plugin-card-top">
     525                <div class="name column-name">
     526                    <h3>
     527                        <a href="<?php echo esc_url( $details_link ); ?>" class="thickbox open-plugin-details-modal">
     528                        <?php echo $title; ?>
     529                        <img src="<?php echo esc_attr( $plugin_icon_url ) ?>" class="plugin-icon" alt="">
     530                        </a>
     531                    </h3>
     532                </div>
     533                <div class="action-links">
     534                    <?php
     535                        if ( $action_links ) {
     536                            echo '<ul class="plugin-action-buttons"><li>' . implode( '</li><li>', $action_links ) . '</li></ul>';
     537                        }
     538                    ?>
     539                </div>
     540                <div class="desc column-description">
     541                    <p><?php echo $description; ?></p>
     542                    <p class="authors"><?php echo $author; ?></p>
     543                </div>
     544            </div>
     545            <div class="plugin-card-bottom">
     546                <div class="vers column-rating">
     547                    <?php wp_star_rating( array( 'rating' => $plugin['rating'], 'type' => 'percent', 'number' => $plugin['num_ratings'] ) ); ?>
     548                    <span class="num-ratings" aria-hidden="true">(<?php echo number_format_i18n( $plugin['num_ratings'] ); ?>)</span>
     549                </div>
     550                <div class="column-updated">
     551                    <strong><?php _e( 'Last Updated:' ); ?></strong> <?php printf( __( '%s ago' ), human_time_diff( $last_updated_timestamp ) ); ?>
     552                </div>
     553                <div class="column-downloaded">
     554                    <?php
     555                    if ( $plugin['active_installs'] >= 1000000 ) {
     556                        $active_installs_text = _x( '1+ Million', 'Active plugin installs' );
     557                    } elseif ( 0 == $plugin['active_installs'] ) {
     558                        $active_installs_text = _x( 'Less Than 10', 'Active plugin installs' );
     559                    } else {
     560                        $active_installs_text = number_format_i18n( $plugin['active_installs'] ) . '+';
     561                    }
     562                    printf( __( '%s Active Installs' ), $active_installs_text );
     563                    ?>
     564                </div>
     565                <div class="column-compatibility">
     566                    <?php
     567                    $wp_version = get_bloginfo( 'version' );
     568
     569                    if ( ! empty( $plugin['tested'] ) && version_compare( substr( $wp_version, 0, strlen( $plugin['tested'] ) ), $plugin['tested'], '>' ) ) {
     570                        echo '<span class="compatibility-untested">' . __( 'Untested with your version of WordPress' ) . '</span>';
     571                    } elseif ( ! empty( $plugin['requires'] ) && version_compare( substr( $wp_version, 0, strlen( $plugin['requires'] ) ), $plugin['requires'], '<' ) ) {
     572                        echo '<span class="compatibility-incompatible">' . __( '<strong>Incompatible</strong> with your version of WordPress' ) . '</span>';
     573                    } else {
     574                        echo '<span class="compatibility-compatible">' . __( '<strong>Compatible</strong> with your version of WordPress' ) . '</span>';
     575                    }
     576                    ?>
     577                </div>
     578            </div>
     579        </div>
     580        <?php
     581        }
     582
     583        // Close off the group divs of the last one
     584        if ( ! empty( $group ) ) {
     585            echo '</div></div>';
     586        }
     587    }
    596588}
  • src/wp-admin/includes/class-wp-plugins-list-table.php

    diff --git a/src/wp-admin/includes/class-wp-plugins-list-table.php b/src/wp-admin/includes/class-wp-plugins-list-table.php
    index 136fbd4c73..8622411681 100644
    a b  
    1717 */
    1818class WP_Plugins_List_Table extends WP_List_Table {
    1919
    20         /**
    21          * Constructor.
    22          *
    23          * @since 3.1.0
    24          * @access public
    25          *
    26          * @see WP_List_Table::__construct() for more information on default arguments.
    27          *
    28          * @global string $status
    29          * @global int    $page
    30          *
    31          * @param array $args An associative array of arguments.
    32          */
    33         public function __construct( $args = array() ) {
    34                 global $status, $page;
    35 
    36                 parent::__construct( array(
    37                         'plural' => 'plugins',
    38                         'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
    39                 ) );
    40 
    41                 $status = 'all';
    42                 if ( isset( $_REQUEST['plugin_status'] ) && in_array( $_REQUEST['plugin_status'], array( 'active', 'inactive', 'recently_activated', 'upgrade', 'mustuse', 'dropins', 'search' ) ) )
    43                         $status = $_REQUEST['plugin_status'];
    44 
    45                 if ( isset($_REQUEST['s']) )
    46                         $_SERVER['REQUEST_URI'] = add_query_arg('s', wp_unslash($_REQUEST['s']) );
    47 
    48                 $page = $this->get_pagenum();
    49         }
    50 
    51         /**
    52          * @return array
    53          */
    54         protected function get_table_classes() {
    55                 return array( 'widefat', $this->_args['plural'] );
    56         }
    57 
    58         /**
    59          * @return bool
    60          */
    61         public function ajax_user_can() {
    62                 return current_user_can('activate_plugins');
    63         }
    64 
    65         /**
    66          *
    67          * @global string $status
    68          * @global array  $plugins
    69          * @global array  $totals
    70          * @global int    $page
    71          * @global string $orderby
    72          * @global string $order
    73          * @global string $s
    74          */
    75         public function prepare_items() {
    76                 global $status, $plugins, $totals, $page, $orderby, $order, $s;
    77 
    78                 wp_reset_vars( array( 'orderby', 'order' ) );
    79 
    80                 /**
    81                  * Filters the full array of plugins to list in the Plugins list table.
    82                  *
    83                  * @since 3.0.0
    84                  *
    85                  * @see get_plugins()
    86                  *
    87                  * @param array $all_plugins An array of plugins to display in the list table.
    88                  */
    89                 $all_plugins = apply_filters( 'all_plugins', get_plugins() );
    90 
    91                 $plugins = array(
    92                         'all'                => $all_plugins,
    93                         'search'             => array(),
    94                         'active'             => array(),
    95                         'inactive'           => array(),
    96                         'recently_activated' => array(),
    97                         'upgrade'            => array(),
    98                         'mustuse'            => array(),
    99                         'dropins'            => array(),
    100                 );
    101 
    102                 $screen = $this->screen;
    103 
    104                 if ( ! is_multisite() || ( $screen->in_admin( 'network' ) && current_user_can( 'manage_network_plugins' ) ) ) {
    105 
    106                         /**
    107                          * Filters whether to display the advanced plugins list table.
    108                          *
    109                          * There are two types of advanced plugins - must-use and drop-ins -
    110                          * which can be used in a single site or Multisite network.
    111                          *
    112                          * The $type parameter allows you to differentiate between the type of advanced
    113                          * plugins to filter the display of. Contexts include 'mustuse' and 'dropins'.
    114                          *
    115                          * @since 3.0.0
    116                          *
    117                          * @param bool   $show Whether to show the advanced plugins for the specified
    118                          *                     plugin type. Default true.
    119                          * @param string $type The plugin type. Accepts 'mustuse', 'dropins'.
    120                          */
    121                         if ( apply_filters( 'show_advanced_plugins', true, 'mustuse' ) ) {
    122                                 $plugins['mustuse'] = get_mu_plugins();
    123                         }
    124 
    125                         /** This action is documented in wp-admin/includes/class-wp-plugins-list-table.php */
    126                         if ( apply_filters( 'show_advanced_plugins', true, 'dropins' ) )
    127                                 $plugins['dropins'] = get_dropins();
    128 
    129                         if ( current_user_can( 'update_plugins' ) ) {
    130                                 $current = get_site_transient( 'update_plugins' );
    131                                 foreach ( (array) $plugins['all'] as $plugin_file => $plugin_data ) {
    132                                         if ( isset( $current->response[ $plugin_file ] ) ) {
    133                                                 $plugins['all'][ $plugin_file ]['update'] = true;
    134                                                 $plugins['upgrade'][ $plugin_file ] = $plugins['all'][ $plugin_file ];
    135                                         }
    136                                 }
    137                         }
    138                 }
    139 
    140                 if ( ! $screen->in_admin( 'network' ) ) {
    141                         $show = current_user_can( 'manage_network_plugins' );
    142                         /**
    143                          * Filters whether to display network-active plugins alongside plugins active for the current site.
    144                          *
    145                          * This also controls the display of inactive network-only plugins (plugins with
    146                          * "Network: true" in the plugin header).
    147                          *
    148                          * Plugins cannot be network-activated or network-deactivated from this screen.
    149                          *
    150                          * @since 4.4.0
    151                          *
    152                          * @param bool $show Whether to show network-active plugins. Default is whether the current
    153                          *                   user can manage network plugins (ie. a Super Admin).
    154                          */
    155                         $show_network_active = apply_filters( 'show_network_active_plugins', $show );
    156                 }
    157 
    158                 set_transient( 'plugin_slugs', array_keys( $plugins['all'] ), DAY_IN_SECONDS );
    159 
    160                 if ( $screen->in_admin( 'network' ) ) {
    161                         $recently_activated = get_site_option( 'recently_activated', array() );
    162                 } else {
    163                         $recently_activated = get_option( 'recently_activated', array() );
    164                 }
    165 
    166                 foreach ( $recently_activated as $key => $time ) {
    167                         if ( $time + WEEK_IN_SECONDS < time() ) {
    168                                 unset( $recently_activated[$key] );
    169                         }
    170                 }
    171 
    172                 if ( $screen->in_admin( 'network' ) ) {
    173                         update_site_option( 'recently_activated', $recently_activated );
    174                 } else {
    175                         update_option( 'recently_activated', $recently_activated );
    176                 }
    177 
    178                 $plugin_info = get_site_transient( 'update_plugins' );
    179 
    180                 foreach ( (array) $plugins['all'] as $plugin_file => $plugin_data ) {
    181                         // Extra info if known. array_merge() ensures $plugin_data has precedence if keys collide.
    182                         if ( isset( $plugin_info->response[ $plugin_file ] ) ) {
    183                                 $plugins['all'][ $plugin_file ] = $plugin_data = array_merge( (array) $plugin_info->response[ $plugin_file ], $plugin_data );
    184                                 // Make sure that $plugins['upgrade'] also receives the extra info since it is used on ?plugin_status=upgrade
    185                                 if ( isset( $plugins['upgrade'][ $plugin_file ] ) ) {
    186                                         $plugins['upgrade'][ $plugin_file ] = $plugin_data = array_merge( (array) $plugin_info->response[ $plugin_file ], $plugin_data );
    187                                 }
    188 
    189                         } elseif ( isset( $plugin_info->no_update[ $plugin_file ] ) ) {
    190                                 $plugins['all'][ $plugin_file ] = $plugin_data = array_merge( (array) $plugin_info->no_update[ $plugin_file ], $plugin_data );
    191                                 // Make sure that $plugins['upgrade'] also receives the extra info since it is used on ?plugin_status=upgrade
    192                                 if ( isset( $plugins['upgrade'][ $plugin_file ] ) ) {
    193                                         $plugins['upgrade'][ $plugin_file ] = $plugin_data = array_merge( (array) $plugin_info->no_update[ $plugin_file ], $plugin_data );
    194                                 }
    195                         }
    196 
    197                         // Filter into individual sections
    198                         if ( is_multisite() && ! $screen->in_admin( 'network' ) && is_network_only_plugin( $plugin_file ) && ! is_plugin_active( $plugin_file ) ) {
    199                                 if ( $show_network_active ) {
    200                                         // On the non-network screen, show inactive network-only plugins if allowed
    201                                         $plugins['inactive'][ $plugin_file ] = $plugin_data;
    202                                 } else {
    203                                         // On the non-network screen, filter out network-only plugins as long as they're not individually active
    204                                         unset( $plugins['all'][ $plugin_file ] );
    205                                 }
    206                         } elseif ( ! $screen->in_admin( 'network' ) && is_plugin_active_for_network( $plugin_file ) ) {
    207                                 if ( $show_network_active ) {
    208                                         // On the non-network screen, show network-active plugins if allowed
    209                                         $plugins['active'][ $plugin_file ] = $plugin_data;
    210                                 } else {
    211                                         // On the non-network screen, filter out network-active plugins
    212                                         unset( $plugins['all'][ $plugin_file ] );
    213                                 }
    214                         } elseif ( ( ! $screen->in_admin( 'network' ) && is_plugin_active( $plugin_file ) )
    215                                 || ( $screen->in_admin( 'network' ) && is_plugin_active_for_network( $plugin_file ) ) ) {
    216                                 // On the non-network screen, populate the active list with plugins that are individually activated
    217                                 // On the network-admin screen, populate the active list with plugins that are network activated
    218                                 $plugins['active'][ $plugin_file ] = $plugin_data;
    219                         } else {
    220                                 if ( isset( $recently_activated[ $plugin_file ] ) ) {
    221                                         // Populate the recently activated list with plugins that have been recently activated
    222                                         $plugins['recently_activated'][ $plugin_file ] = $plugin_data;
    223                                 }
    224                                 // Populate the inactive list with plugins that aren't activated
    225                                 $plugins['inactive'][ $plugin_file ] = $plugin_data;
    226                         }
    227                 }
    228 
    229                 if ( strlen( $s ) ) {
    230                         $status = 'search';
    231                         $plugins['search'] = array_filter( $plugins['all'], array( $this, '_search_callback' ) );
    232                 }
    233 
    234                 $totals = array();
    235                 foreach ( $plugins as $type => $list )
    236                         $totals[ $type ] = count( $list );
    237 
    238                 if ( empty( $plugins[ $status ] ) && !in_array( $status, array( 'all', 'search' ) ) )
    239                         $status = 'all';
    240 
    241                 $this->items = array();
    242                 foreach ( $plugins[ $status ] as $plugin_file => $plugin_data ) {
    243                         // Translate, Don't Apply Markup, Sanitize HTML
    244                         $this->items[$plugin_file] = _get_plugin_data_markup_translate( $plugin_file, $plugin_data, false, true );
    245                 }
    246 
    247                 $total_this_page = $totals[ $status ];
    248 
    249                 $js_plugins = array();
    250                 foreach ( $plugins as $key => $list ) {
    251                         $js_plugins[ $key ] = array_keys( (array) $list );
    252                 }
    253 
    254                 wp_localize_script( 'updates', '_wpUpdatesItemCounts', array(
    255                         'plugins' => $js_plugins,
    256                         'totals'  => wp_get_update_data(),
    257                 ) );
    258 
    259                 if ( ! $orderby ) {
    260                         $orderby = 'Name';
    261                 } else {
    262                         $orderby = ucfirst( $orderby );
    263                 }
    264 
    265                 $order = strtoupper( $order );
    266 
    267                 uasort( $this->items, array( $this, '_order_callback' ) );
    268 
    269                 $plugins_per_page = $this->get_items_per_page( str_replace( '-', '_', $screen->id . '_per_page' ), 999 );
    270 
    271                 $start = ( $page - 1 ) * $plugins_per_page;
    272 
    273                 if ( $total_this_page > $plugins_per_page )
    274                         $this->items = array_slice( $this->items, $start, $plugins_per_page );
    275 
    276                 $this->set_pagination_args( array(
    277                         'total_items' => $total_this_page,
    278                         'per_page' => $plugins_per_page,
    279                 ) );
    280         }
    281 
    282         /**
    283          * @global string $s URL encoded search term.
    284          *
    285          * @param array $plugin
    286          * @return bool
    287          */
    288         public function _search_callback( $plugin ) {
    289                 global $s;
    290 
    291                 foreach ( $plugin as $value ) {
    292                         if ( is_string( $value ) && false !== stripos( strip_tags( $value ), urldecode( $s ) ) ) {
    293                                 return true;
    294                         }
    295                 }
    296 
    297                 return false;
    298         }
    299 
    300         /**
    301          * @global string $orderby
    302          * @global string $order
    303          * @param array $plugin_a
    304          * @param array $plugin_b
    305          * @return int
    306          */
    307         public function _order_callback( $plugin_a, $plugin_b ) {
    308                 global $orderby, $order;
    309 
    310                 $a = $plugin_a[$orderby];
    311                 $b = $plugin_b[$orderby];
    312 
    313                 if ( $a == $b )
    314                         return 0;
    315 
    316                 if ( 'DESC' === $order ) {
    317                         return strcasecmp( $b, $a );
    318                 } else {
    319                         return strcasecmp( $a, $b );
    320                 }
    321         }
    322 
    323         /**
    324          *
    325          * @global array $plugins
    326          */
    327         public function no_items() {
    328                 global $plugins;
    329 
    330                 if ( ! empty( $_REQUEST['s'] ) ) {
    331                         $s = esc_html( wp_unslash( $_REQUEST['s'] ) );
    332 
    333                         printf( __( 'No plugins found for &#8220;%s&#8221;.' ), $s );
    334 
    335                         // We assume that somebody who can install plugins in multisite is experienced enough to not need this helper link.
    336                         if ( ! is_multisite() && current_user_can( 'install_plugins' ) ) {
    337                                 echo ' <a href="' . esc_url( admin_url( 'plugin-install.php?tab=search&s=' . urlencode( $s ) ) ) . '">' . __( 'Search for plugins in the WordPress Plugin Directory.' ) . '</a>';
    338                         }
    339                 } elseif ( ! empty( $plugins['all'] ) )
    340                         _e( 'No plugins found.' );
    341                 else
    342                         _e( 'You do not appear to have any plugins available at this time.' );
    343         }
    344 
    345         /**
    346          * Displays the search box.
    347          *
    348          * @since 4.6.0
    349          * @access public
    350          *
    351          * @param string $text     The 'submit' button label.
    352          * @param string $input_id ID attribute value for the search input field.
    353          */
    354         public function search_box( $text, $input_id ) {
    355                 if ( empty( $_REQUEST['s'] ) && ! $this->has_items() ) {
    356                         return;
    357                 }
    358 
    359                 $input_id = $input_id . '-search-input';
    360 
    361                 if ( ! empty( $_REQUEST['orderby'] ) ) {
    362                         echo '<input type="hidden" name="orderby" value="' . esc_attr( $_REQUEST['orderby'] ) . '" />';
    363                 }
    364                 if ( ! empty( $_REQUEST['order'] ) ) {
    365                         echo '<input type="hidden" name="order" value="' . esc_attr( $_REQUEST['order'] ) . '" />';
    366                 }
    367                 ?>
    368                 <p class="search-box">
    369                         <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>"><?php echo $text; ?>:</label>
    370                         <input type="search" id="<?php echo esc_attr( $input_id ); ?>" class="wp-filter-search" name="s" value="<?php _admin_search_query(); ?>" placeholder="<?php esc_attr_e( 'Search installed plugins...' ); ?>"/>
    371                         <?php submit_button( $text, 'hide-if-js', '', false, array( 'id' => 'search-submit' ) ); ?>
    372                 </p>
    373                 <?php
    374         }
    375 
    376         /**
    377          *
    378          * @global string $status
    379          * @return array
    380          */
    381         public function get_columns() {
    382                 global $status;
    383 
    384                 return array(
    385                         'cb'          => !in_array( $status, array( 'mustuse', 'dropins' ) ) ? '<input type="checkbox" />' : '',
    386                         'name'        => __( 'Plugin' ),
    387                         'description' => __( 'Description' ),
    388                 );
    389         }
    390 
    391         /**
    392          * @return array
    393          */
    394         protected function get_sortable_columns() {
    395                 return array();
    396         }
    397 
    398         /**
    399          *
    400          * @global array $totals
    401          * @global string $status
    402          * @return array
    403          */
    404         protected function get_views() {
    405                 global $totals, $status;
    406 
    407                 $status_links = array();
    408                 foreach ( $totals as $type => $count ) {
    409                         if ( !$count )
    410                                 continue;
    411 
    412                         switch ( $type ) {
    413                                 case 'all':
    414                                         $text = _nx( 'All <span class="count">(%s)</span>', 'All <span class="count">(%s)</span>', $count, 'plugins' );
    415                                         break;
    416                                 case 'active':
    417                                         $text = _n( 'Active <span class="count">(%s)</span>', 'Active <span class="count">(%s)</span>', $count );
    418                                         break;
    419                                 case 'recently_activated':
    420                                         $text = _n( 'Recently Active <span class="count">(%s)</span>', 'Recently Active <span class="count">(%s)</span>', $count );
    421                                         break;
    422                                 case 'inactive':
    423                                         $text = _n( 'Inactive <span class="count">(%s)</span>', 'Inactive <span class="count">(%s)</span>', $count );
    424                                         break;
    425                                 case 'mustuse':
    426                                         $text = _n( 'Must-Use <span class="count">(%s)</span>', 'Must-Use <span class="count">(%s)</span>', $count );
    427                                         break;
    428                                 case 'dropins':
    429                                         $text = _n( 'Drop-ins <span class="count">(%s)</span>', 'Drop-ins <span class="count">(%s)</span>', $count );
    430                                         break;
    431                                 case 'upgrade':
    432                                         $text = _n( 'Update Available <span class="count">(%s)</span>', 'Update Available <span class="count">(%s)</span>', $count );
    433                                         break;
    434                         }
    435 
    436                         if ( 'search' !== $type ) {
    437                                 $status_links[$type] = sprintf( "<a href='%s' %s>%s</a>",
    438                                         add_query_arg('plugin_status', $type, 'plugins.php'),
    439                                         ( $type === $status ) ? ' class="current"' : '',
    440                                         sprintf( $text, number_format_i18n( $count ) )
    441                                         );
    442                         }
    443                 }
    444 
    445                 return $status_links;
    446         }
    447 
    448         /**
    449          *
    450          * @global string $status
    451          * @return array
    452          */
    453         protected function get_bulk_actions() {
    454                 global $status;
    455 
    456                 $actions = array();
    457 
    458                 if ( 'active' != $status )
    459                         $actions['activate-selected'] = $this->screen->in_admin( 'network' ) ? __( 'Network Activate' ) : __( 'Activate' );
    460 
    461                 if ( 'inactive' != $status && 'recent' != $status )
    462                         $actions['deactivate-selected'] = $this->screen->in_admin( 'network' ) ? __( 'Network Deactivate' ) : __( 'Deactivate' );
    463 
    464                 if ( !is_multisite() || $this->screen->in_admin( 'network' ) ) {
    465                         if ( current_user_can( 'update_plugins' ) )
    466                                 $actions['update-selected'] = __( 'Update' );
    467                         if ( current_user_can( 'delete_plugins' ) && ( 'active' != $status ) )
    468                                 $actions['delete-selected'] = __( 'Delete' );
    469                 }
    470 
    471                 return $actions;
    472         }
    473 
    474         /**
    475          * @global string $status
    476          * @param string $which
    477          */
    478         public function bulk_actions( $which = '' ) {
    479                 global $status;
    480 
    481                 if ( in_array( $status, array( 'mustuse', 'dropins' ) ) )
    482                         return;
    483 
    484                 parent::bulk_actions( $which );
    485         }
    486 
    487         /**
    488          * @global string $status
    489          * @param string $which
    490          */
    491         protected function extra_tablenav( $which ) {
    492                 global $status;
    493 
    494                 if ( ! in_array($status, array('recently_activated', 'mustuse', 'dropins') ) )
    495                         return;
    496 
    497                 echo '<div class="alignleft actions">';
    498 
    499                 if ( 'recently_activated' == $status ) {
    500                         submit_button( __( 'Clear List' ), '', 'clear-recent-list', false );
    501                 } elseif ( 'top' === $which && 'mustuse' === $status ) {
    502                         /* translators: %s: mu-plugins directory name */
    503                         echo '<p>' . sprintf( __( 'Files in the %s directory are executed automatically.' ),
    504                                 '<code>' . str_replace( ABSPATH, '/', WPMU_PLUGIN_DIR ) . '</code>'
    505                         ) . '</p>';
    506                 } elseif ( 'top' === $which && 'dropins' === $status ) {
    507                         /* translators: %s: wp-content directory name */
    508                         echo '<p>' . sprintf( __( 'Drop-ins are advanced plugins in the %s directory that replace WordPress functionality when present.' ),
    509                                 '<code>' . str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '</code>'
    510                         ) . '</p>';
    511                 }
    512                 echo '</div>';
    513         }
    514 
    515         /**
    516          * @return string
    517          */
    518         public function current_action() {
    519                 if ( isset($_POST['clear-recent-list']) )
    520                         return 'clear-recent-list';
    521 
    522                 return parent::current_action();
    523         }
    524 
    525         /**
    526          *
    527          * @global string $status
    528          */
    529         public function display_rows() {
    530                 global $status;
    531 
    532                 if ( is_multisite() && ! $this->screen->in_admin( 'network' ) && in_array( $status, array( 'mustuse', 'dropins' ) ) )
    533                         return;
    534 
    535                 foreach ( $this->items as $plugin_file => $plugin_data )
    536                         $this->single_row( array( $plugin_file, $plugin_data ) );
    537         }
    538 
    539         /**
    540          * @global string $status
    541          * @global int $page
    542          * @global string $s
    543          * @global array $totals
    544          *
    545          * @param array $item
    546          */
    547         public function single_row( $item ) {
    548                 global $status, $page, $s, $totals;
    549 
    550                 list( $plugin_file, $plugin_data ) = $item;
    551                 $context = $status;
    552                 $screen = $this->screen;
    553 
    554                 // Pre-order.
    555                 $actions = array(
    556                         'deactivate' => '',
    557                         'activate' => '',
    558                         'details' => '',
    559                         'edit' => '',
    560                         'delete' => '',
    561                 );
    562 
    563                 // Do not restrict by default
    564                 $restrict_network_active = false;
    565                 $restrict_network_only = false;
    566 
    567                 if ( 'mustuse' === $context ) {
    568                         $is_active = true;
    569                 } elseif ( 'dropins' === $context ) {
    570                         $dropins = _get_dropins();
    571                         $plugin_name = $plugin_file;
    572                         if ( $plugin_file != $plugin_data['Name'] )
    573                                 $plugin_name .= '<br/>' . $plugin_data['Name'];
    574                         if ( true === ( $dropins[ $plugin_file ][1] ) ) { // Doesn't require a constant
    575                                 $is_active = true;
    576                                 $description = '<p><strong>' . $dropins[ $plugin_file ][0] . '</strong></p>';
    577                         } elseif ( defined( $dropins[ $plugin_file ][1] ) && constant( $dropins[ $plugin_file ][1] ) ) { // Constant is true
    578                                 $is_active = true;
    579                                 $description = '<p><strong>' . $dropins[ $plugin_file ][0] . '</strong></p>';
    580                         } else {
    581                                 $is_active = false;
    582                                 $description = '<p><strong>' . $dropins[ $plugin_file ][0] . ' <span class="error-message">' . __( 'Inactive:' ) . '</span></strong> ' .
    583                                         /* translators: 1: drop-in constant name, 2: wp-config.php */
    584                                         sprintf( __( 'Requires %1$s in %2$s file.' ),
    585                                                 "<code>define('" . $dropins[ $plugin_file ][1] . "', true);</code>",
    586                                                 '<code>wp-config.php</code>'
    587                                         ) . '</p>';
    588                         }
    589                         if ( $plugin_data['Description'] )
    590                                 $description .= '<p>' . $plugin_data['Description'] . '</p>';
    591                 } else {
    592                         if ( $screen->in_admin( 'network' ) ) {
    593                                 $is_active = is_plugin_active_for_network( $plugin_file );
    594                         } else {
    595                                 $is_active = is_plugin_active( $plugin_file );
    596                                 $restrict_network_active = ( is_multisite() && is_plugin_active_for_network( $plugin_file ) );
    597                                 $restrict_network_only = ( is_multisite() && is_network_only_plugin( $plugin_file ) && ! $is_active );
    598                         }
    599 
    600                         if ( $screen->in_admin( 'network' ) ) {
    601                                 if ( $is_active ) {
    602                                         if ( current_user_can( 'manage_network_plugins' ) ) {
    603                                                 /* translators: %s: plugin name */
    604                                                 $actions['deactivate'] = '<a href="' . wp_nonce_url( 'plugins.php?action=deactivate&amp;plugin=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'deactivate-plugin_' . $plugin_file ) . '" aria-label="' . esc_attr( sprintf( _x( 'Network Deactivate %s', 'plugin' ), $plugin_data['Name'] ) ) . '">' . __( 'Network Deactivate' ) . '</a>';
    605                                                 }
    606                                 } else {
    607                                         if ( current_user_can( 'manage_network_plugins' ) ) {
    608                                                 /* translators: %s: plugin name */
    609                                                 $actions['activate'] = '<a href="' . wp_nonce_url( 'plugins.php?action=activate&amp;plugin=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'activate-plugin_' . $plugin_file ) . '" class="edit" aria-label="' . esc_attr( sprintf( _x( 'Network Activate %s', 'plugin' ), $plugin_data['Name'] ) ) . '">' . __( 'Network Activate' ) . '</a>';
    610                                         }
    611                                         if ( current_user_can( 'delete_plugins' ) && ! is_plugin_active( $plugin_file ) ) {
    612                                                 /* translators: %s: plugin name */
    613                                                 $actions['delete'] = '<a href="' . wp_nonce_url( 'plugins.php?action=delete-selected&amp;checked[]=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'bulk-plugins' ) . '" class="delete" aria-label="' . esc_attr( sprintf( _x( 'Delete %s', 'plugin' ), $plugin_data['Name'] ) ) . '">' . __( 'Delete' ) . '</a>';
    614                                         }
    615                                 }
    616                         } else {
    617                                 if ( $restrict_network_active ) {
    618                                         $actions = array(
    619                                                 'network_active' => __( 'Network Active' ),
    620                                         );
    621                                 } elseif ( $restrict_network_only ) {
    622                                         $actions = array(
    623                                                 'network_only' => __( 'Network Only' ),
    624                                         );
    625                                 } elseif ( $is_active ) {
    626                                         /* translators: %s: plugin name */
    627                                         $actions['deactivate'] = '<a href="' . wp_nonce_url( 'plugins.php?action=deactivate&amp;plugin=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'deactivate-plugin_' . $plugin_file ) . '" aria-label="' . esc_attr( sprintf( _x( 'Deactivate %s', 'plugin' ), $plugin_data['Name'] ) ) . '">' . __( 'Deactivate' ) . '</a>';
    628                                 } else {
    629                                         /* translators: %s: plugin name */
    630                                         $actions['activate'] = '<a href="' . wp_nonce_url( 'plugins.php?action=activate&amp;plugin=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'activate-plugin_' . $plugin_file ) . '" class="edit" aria-label="' . esc_attr( sprintf( _x( 'Activate %s', 'plugin' ), $plugin_data['Name'] ) ) . '">' . __( 'Activate' ) . '</a>';
    631 
    632                                         if ( ! is_multisite() && current_user_can( 'delete_plugins' ) ) {
    633                                                 /* translators: %s: plugin name */
    634                                                 $actions['delete'] = '<a href="' . wp_nonce_url( 'plugins.php?action=delete-selected&amp;checked[]=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'bulk-plugins' ) . '" class="delete" aria-label="' . esc_attr( sprintf( _x( 'Delete %s', 'plugin' ), $plugin_data['Name'] ) ) . '">' . __( 'Delete' ) . '</a>';
    635                                         }
    636                                 } // end if $is_active
    637 
    638                          } // end if $screen->in_admin( 'network' )
    639 
    640                         if ( ( ! is_multisite() || $screen->in_admin( 'network' ) ) && current_user_can( 'edit_plugins' ) && is_writable( WP_PLUGIN_DIR . '/' . $plugin_file ) ) {
    641                                 /* translators: %s: plugin name */
    642                                 $actions['edit'] = '<a href="plugin-editor.php?file=' . $plugin_file . '" class="edit" aria-label="' . esc_attr( sprintf( __( 'Edit %s' ), $plugin_data['Name'] ) ) . '">' . __( 'Edit' ) . '</a>';
    643                         }
    644                 } // end if $context
    645 
    646                 $actions = array_filter( $actions );
    647 
    648                 if ( $screen->in_admin( 'network' ) ) {
    649 
    650                         /**
    651                          * Filters the action links displayed for each plugin in the Network Admin Plugins list table.
    652                          *
    653                          * The default action links for the Network plugins list table include
    654                          * 'Network Activate', 'Network Deactivate', 'Edit', and 'Delete'.
    655                          *
    656                          * @since 3.1.0
    657                          *
    658                          * @param array  $actions     An array of plugin action links.
    659                          * @param string $plugin_file Path to the plugin file relative to the plugins directory.
    660                          * @param array  $plugin_data An array of plugin data.
    661                          * @param string $context     The plugin context. Defaults are 'All', 'Active',
    662                          *                            'Inactive', 'Recently Activated', 'Upgrade',
    663                          *                            'Must-Use', 'Drop-ins', 'Search'.
    664                          */
    665                         $actions = apply_filters( 'network_admin_plugin_action_links', $actions, $plugin_file, $plugin_data, $context );
    666 
    667                         /**
    668                          * Filters the list of action links displayed for a specific plugin in the Network Admin Plugins list table.
    669                          *
    670                          * The dynamic portion of the hook name, $plugin_file, refers to the path
    671                          * to the plugin file, relative to the plugins directory.
    672                          *
    673                          * @since 3.1.0
    674                          *
    675                          * @param array  $actions     An array of plugin action links.
    676                          * @param string $plugin_file Path to the plugin file relative to the plugins directory.
    677                          * @param array  $plugin_data An array of plugin data.
    678                          * @param string $context     The plugin context. Defaults are 'All', 'Active',
    679                          *                            'Inactive', 'Recently Activated', 'Upgrade',
    680                          *                            'Must-Use', 'Drop-ins', 'Search'.
    681                          */
    682                         $actions = apply_filters( "network_admin_plugin_action_links_{$plugin_file}", $actions, $plugin_file, $plugin_data, $context );
    683 
    684                 } else {
    685 
    686                         /**
    687                          * Filters the action links displayed for each plugin in the Plugins list table.
    688                          *
    689                          * The default action links for the site plugins list table include
    690                          * 'Activate', 'Deactivate', and 'Edit', for a network site, and
    691                          * 'Activate', 'Deactivate', 'Edit', and 'Delete' for a single site.
    692                          *
    693                          * @since 2.5.0
    694                          * @since 2.6.0 The `$context` parameter was added.
    695                          *
    696                          * @param array  $actions     An array of plugin action links.
    697                          * @param string $plugin_file Path to the plugin file relative to the plugins directory.
    698                          * @param array  $plugin_data An array of plugin data.
    699                          * @param string $context     The plugin context. Defaults are 'All', 'Active',
    700                          *                            'Inactive', 'Recently Activated', 'Upgrade',
    701                          *                            'Must-Use', 'Drop-ins', 'Search'.
    702                          */
    703                         $actions = apply_filters( 'plugin_action_links', $actions, $plugin_file, $plugin_data, $context );
    704 
    705                         /**
    706                          * Filters the list of action links displayed for a specific plugin in the Plugins list table.
    707                          *
    708                          * The dynamic portion of the hook name, $plugin_file, refers to the path
    709                          * to the plugin file, relative to the plugins directory.
    710                          *
    711                          * @since 2.7.0
    712                          *
    713                          * @param array  $actions     An array of plugin action links.
    714                          * @param string $plugin_file Path to the plugin file relative to the plugins directory.
    715                          * @param array  $plugin_data An array of plugin data.
    716                          * @param string $context     The plugin context. Defaults are 'All', 'Active',
    717                          *                            'Inactive', 'Recently Activated', 'Upgrade',
    718                          *                            'Must-Use', 'Drop-ins', 'Search'.
    719                          */
    720                         $actions = apply_filters( "plugin_action_links_{$plugin_file}", $actions, $plugin_file, $plugin_data, $context );
    721 
    722                 }
    723 
    724                 $class = $is_active ? 'active' : 'inactive';
    725                 $checkbox_id =  "checkbox_" . md5($plugin_data['Name']);
    726                 if ( $restrict_network_active || $restrict_network_only || in_array( $status, array( 'mustuse', 'dropins' ) ) ) {
    727                         $checkbox = '';
    728                 } else {
    729                         $checkbox = "<label class='screen-reader-text' for='" . $checkbox_id . "' >" . sprintf( __( 'Select %s' ), $plugin_data['Name'] ) . "</label>"
    730                                 . "<input type='checkbox' name='checked[]' value='" . esc_attr( $plugin_file ) . "' id='" . $checkbox_id . "' />";
    731                 }
    732                 if ( 'dropins' != $context ) {
    733                         $description = '<p>' . ( $plugin_data['Description'] ? $plugin_data['Description'] : '&nbsp;' ) . '</p>';
    734                         $plugin_name = $plugin_data['Name'];
    735                 }
    736 
    737                 if ( ! empty( $totals['upgrade'] ) && ! empty( $plugin_data['update'] ) )
    738                         $class .= ' update';
    739 
    740                 $plugin_slug = isset( $plugin_data['slug'] ) ? $plugin_data['slug'] : sanitize_title( $plugin_name );
    741                 printf( '<tr class="%s" data-slug="%s" data-plugin="%s">',
    742                         esc_attr( $class ),
    743                         esc_attr( $plugin_slug ),
    744                         esc_attr( $plugin_file )
    745                 );
    746 
    747                 list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
    748 
    749                 foreach ( $columns as $column_name => $column_display_name ) {
    750                         $extra_classes = '';
    751                         if ( in_array( $column_name, $hidden ) ) {
    752                                 $extra_classes = ' hidden';
    753                         }
    754 
    755                         switch ( $column_name ) {
    756                                 case 'cb':
    757                                         echo "<th scope='row' class='check-column'>$checkbox</th>";
    758                                         break;
    759                                 case 'name':
    760                                         echo "<td class='plugin-title column-primary'><strong>$plugin_name</strong>";
    761                                         echo $this->row_actions( $actions, true );
    762                                         echo "</td>";
    763                                         break;
    764                                 case 'description':
    765                                         $classes = 'column-description desc';
    766 
    767                                         echo "<td class='$classes{$extra_classes}'>
    768                                                 <div class='plugin-description'>$description</div>
    769                                                 <div class='$class second plugin-version-author-uri'>";
    770 
    771                                         $plugin_meta = array();
    772                                         if ( !empty( $plugin_data['Version'] ) )
    773                                                 $plugin_meta[] = sprintf( __( 'Version %s' ), $plugin_data['Version'] );
    774                                         if ( !empty( $plugin_data['Author'] ) ) {
    775                                                 $author = $plugin_data['Author'];
    776                                                 if ( !empty( $plugin_data['AuthorURI'] ) )
    777                                                         $author = '<a href="' . $plugin_data['AuthorURI'] . '">' . $plugin_data['Author'] . '</a>';
    778                                                 $plugin_meta[] = sprintf( __( 'By %s' ), $author );
    779                                         }
    780 
    781                                         // Details link using API info, if available
    782                                         if ( isset( $plugin_data['slug'] ) && current_user_can( 'install_plugins' ) ) {
    783                                                 $plugin_meta[] = sprintf( '<a href="%s" class="thickbox open-plugin-details-modal" aria-label="%s" data-title="%s">%s</a>',
    784                                                         esc_url( network_admin_url( 'plugin-install.php?tab=plugin-information&plugin=' . $plugin_data['slug'] .
    785                                                                 '&TB_iframe=true&width=600&height=550' ) ),
    786                                                         esc_attr( sprintf( __( 'More information about %s' ), $plugin_name ) ),
    787                                                         esc_attr( $plugin_name ),
    788                                                         __( 'View details' )
    789                                                 );
    790                                         } elseif ( ! empty( $plugin_data['PluginURI'] ) ) {
    791                                                 $plugin_meta[] = sprintf( '<a href="%s">%s</a>',
    792                                                         esc_url( $plugin_data['PluginURI'] ),
    793                                                         __( 'Visit plugin site' )
    794                                                 );
    795                                         }
    796 
    797                                         /**
    798                                          * Filters the array of row meta for each plugin in the Plugins list table.
    799                                          *
    800                                          * @since 2.8.0
    801                                          *
    802                                          * @param array  $plugin_meta An array of the plugin's metadata,
    803                                          *                            including the version, author,
    804                                          *                            author URI, and plugin URI.
    805                                          * @param string $plugin_file Path to the plugin file, relative to the plugins directory.
    806                                          * @param array  $plugin_data An array of plugin data.
    807                                          * @param string $status      Status of the plugin. Defaults are 'All', 'Active',
    808                                          *                            'Inactive', 'Recently Activated', 'Upgrade', 'Must-Use',
    809                                          *                            'Drop-ins', 'Search'.
    810                                          */
    811                                         $plugin_meta = apply_filters( 'plugin_row_meta', $plugin_meta, $plugin_file, $plugin_data, $status );
    812                                         echo implode( ' | ', $plugin_meta );
    813 
    814                                         echo "</div></td>";
    815                                         break;
    816                                 default:
    817                                         $classes = "$column_name column-$column_name $class";
    818 
    819                                         echo "<td class='$classes{$extra_classes}'>";
    820 
    821                                         /**
    822                                          * Fires inside each custom column of the Plugins list table.
    823                                          *
    824                                          * @since 3.1.0
    825                                          *
    826                                          * @param string $column_name Name of the column.
    827                                          * @param string $plugin_file Path to the plugin file.
    828                                          * @param array  $plugin_data An array of plugin data.
    829                                          */
    830                                         do_action( 'manage_plugins_custom_column', $column_name, $plugin_file, $plugin_data );
    831 
    832                                         echo "</td>";
    833                         }
    834                 }
    835 
    836                 echo "</tr>";
    837 
    838                 /**
    839                  * Fires after each row in the Plugins list table.
    840                  *
    841                  * @since 2.3.0
    842                  *
    843                  * @param string $plugin_file Path to the plugin file, relative to the plugins directory.
    844                  * @param array  $plugin_data An array of plugin data.
    845                  * @param string $status      Status of the plugin. Defaults are 'All', 'Active',
    846                  *                            'Inactive', 'Recently Activated', 'Upgrade', 'Must-Use',
    847                  *                            'Drop-ins', 'Search'.
    848                  */
    849                 do_action( 'after_plugin_row', $plugin_file, $plugin_data, $status );
    850 
    851                 /**
    852                  * Fires after each specific row in the Plugins list table.
    853                  *
    854                  * The dynamic portion of the hook name, `$plugin_file`, refers to the path
    855                  * to the plugin file, relative to the plugins directory.
    856                  *
    857                  * @since 2.7.0
    858                  *
    859                  * @param string $plugin_file Path to the plugin file, relative to the plugins directory.
    860                  * @param array  $plugin_data An array of plugin data.
    861                  * @param string $status      Status of the plugin. Defaults are 'All', 'Active',
    862                  *                            'Inactive', 'Recently Activated', 'Upgrade', 'Must-Use',
    863                  *                            'Drop-ins', 'Search'.
    864                  */
    865                 do_action( "after_plugin_row_{$plugin_file}", $plugin_file, $plugin_data, $status );
    866         }
    867 
    868         /**
    869          * Gets the name of the primary column for this specific list table.
    870          *
    871          * @since 4.3.0
    872          * @access protected
    873          *
    874          * @return string Unalterable name for the primary column, in this case, 'name'.
    875          */
    876         protected function get_primary_column_name() {
    877                 return 'name';
    878         }
     20    /**
     21     * Constructor.
     22     *
     23     * @since 3.1.0
     24     * @access public
     25     *
     26     * @see WP_List_Table::__construct() for more information on default arguments.
     27     *
     28     * @global string $status
     29     * @global int    $page
     30     *
     31     * @param array $args An associative array of arguments.
     32     */
     33    public function __construct( $args = array() ) {
     34        global $status, $page;
     35
     36        parent::__construct( array(
     37            'plural' => 'plugins',
     38            'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
     39        ) );
     40
     41        $status = 'all';
     42        if ( isset( $_REQUEST['plugin_status'] ) && in_array( $_REQUEST['plugin_status'], array( 'active', 'inactive', 'recently_activated', 'upgrade', 'mustuse', 'dropins', 'search' ) ) )
     43            $status = $_REQUEST['plugin_status'];
     44
     45        if ( isset($_REQUEST['s']) )
     46            $_SERVER['REQUEST_URI'] = add_query_arg('s', wp_unslash($_REQUEST['s']) );
     47
     48        $page = $this->get_pagenum();
     49    }
     50
     51    /**
     52     * @return array
     53     */
     54    protected function get_table_classes() {
     55        return array( 'widefat', $this->_args['plural'] );
     56    }
     57
     58    /**
     59     * @return bool
     60     */
     61    public function ajax_user_can() {
     62        return current_user_can('activate_plugins');
     63    }
     64
     65    public function prepare_items() {
     66        $status = wp_assign_request_var('status');
     67        $plugin = wp_assign_request_var('plugin');
     68        $totals = wp_assign_request_var('totals');
     69        $page = wp_assign_request_var('page');
     70        $orderby = wp_assign_request_var('orderby');
     71        $order = wp_assign_request_var('order');
     72        $s = wp_assign_request_var('s');
     73
     74        /**
     75         * Filters the full array of plugins to list in the Plugins list table.
     76         *
     77         * @since 3.0.0
     78         *
     79         * @see get_plugins()
     80         *
     81         * @param array $all_plugins An array of plugins to display in the list table.
     82         */
     83        $all_plugins = apply_filters( 'all_plugins', get_plugins() );
     84
     85        $plugins = array(
     86            'all'                => $all_plugins,
     87            'search'             => array(),
     88            'active'             => array(),
     89            'inactive'           => array(),
     90            'recently_activated' => array(),
     91            'upgrade'            => array(),
     92            'mustuse'            => array(),
     93            'dropins'            => array(),
     94        );
     95
     96        $screen = $this->screen;
     97
     98        if ( ! is_multisite() || ( $screen->in_admin( 'network' ) && current_user_can( 'manage_network_plugins' ) ) ) {
     99
     100            /**
     101             * Filters whether to display the advanced plugins list table.
     102             *
     103             * There are two types of advanced plugins - must-use and drop-ins -
     104             * which can be used in a single site or Multisite network.
     105             *
     106             * The $type parameter allows you to differentiate between the type of advanced
     107             * plugins to filter the display of. Contexts include 'mustuse' and 'dropins'.
     108             *
     109             * @since 3.0.0
     110             *
     111             * @param bool   $show Whether to show the advanced plugins for the specified
     112             *                     plugin type. Default true.
     113             * @param string $type The plugin type. Accepts 'mustuse', 'dropins'.
     114             */
     115            if ( apply_filters( 'show_advanced_plugins', true, 'mustuse' ) ) {
     116                $plugins['mustuse'] = get_mu_plugins();
     117            }
     118
     119            /** This action is documented in wp-admin/includes/class-wp-plugins-list-table.php */
     120            if ( apply_filters( 'show_advanced_plugins', true, 'dropins' ) )
     121                $plugins['dropins'] = get_dropins();
     122
     123            if ( current_user_can( 'update_plugins' ) ) {
     124                $current = get_site_transient( 'update_plugins' );
     125                foreach ( (array) $plugins['all'] as $plugin_file => $plugin_data ) {
     126                    if ( isset( $current->response[ $plugin_file ] ) ) {
     127                        $plugins['all'][ $plugin_file ]['update'] = true;
     128                        $plugins['upgrade'][ $plugin_file ] = $plugins['all'][ $plugin_file ];
     129                    }
     130                }
     131            }
     132        }
     133
     134        if ( ! $screen->in_admin( 'network' ) ) {
     135            $show = current_user_can( 'manage_network_plugins' );
     136            /**
     137             * Filters whether to display network-active plugins alongside plugins active for the current site.
     138             *
     139             * This also controls the display of inactive network-only plugins (plugins with
     140             * "Network: true" in the plugin header).
     141             *
     142             * Plugins cannot be network-activated or network-deactivated from this screen.
     143             *
     144             * @since 4.4.0
     145             *
     146             * @param bool $show Whether to show network-active plugins. Default is whether the current
     147             *                   user can manage network plugins (ie. a Super Admin).
     148             */
     149            $show_network_active = apply_filters( 'show_network_active_plugins', $show );
     150        }
     151
     152        set_transient( 'plugin_slugs', array_keys( $plugins['all'] ), DAY_IN_SECONDS );
     153
     154        if ( $screen->in_admin( 'network' ) ) {
     155            $recently_activated = get_site_option( 'recently_activated', array() );
     156        } else {
     157            $recently_activated = get_option( 'recently_activated', array() );
     158        }
     159
     160        foreach ( $recently_activated as $key => $time ) {
     161            if ( $time + WEEK_IN_SECONDS < time() ) {
     162                unset( $recently_activated[$key] );
     163            }
     164        }
     165
     166        if ( $screen->in_admin( 'network' ) ) {
     167            update_site_option( 'recently_activated', $recently_activated );
     168        } else {
     169            update_option( 'recently_activated', $recently_activated );
     170        }
     171
     172        $plugin_info = get_site_transient( 'update_plugins' );
     173
     174        foreach ( (array) $plugins['all'] as $plugin_file => $plugin_data ) {
     175            // Extra info if known. array_merge() ensures $plugin_data has precedence if keys collide.
     176            if ( isset( $plugin_info->response[ $plugin_file ] ) ) {
     177                $plugins['all'][ $plugin_file ] = $plugin_data = array_merge( (array) $plugin_info->response[ $plugin_file ], $plugin_data );
     178                // Make sure that $plugins['upgrade'] also receives the extra info since it is used on ?plugin_status=upgrade
     179                if ( isset( $plugins['upgrade'][ $plugin_file ] ) ) {
     180                    $plugins['upgrade'][ $plugin_file ] = $plugin_data = array_merge( (array) $plugin_info->response[ $plugin_file ], $plugin_data );
     181                }
     182
     183            } elseif ( isset( $plugin_info->no_update[ $plugin_file ] ) ) {
     184                $plugins['all'][ $plugin_file ] = $plugin_data = array_merge( (array) $plugin_info->no_update[ $plugin_file ], $plugin_data );
     185                // Make sure that $plugins['upgrade'] also receives the extra info since it is used on ?plugin_status=upgrade
     186                if ( isset( $plugins['upgrade'][ $plugin_file ] ) ) {
     187                    $plugins['upgrade'][ $plugin_file ] = $plugin_data = array_merge( (array) $plugin_info->no_update[ $plugin_file ], $plugin_data );
     188                }
     189            }
     190
     191            // Filter into individual sections
     192            if ( is_multisite() && ! $screen->in_admin( 'network' ) && is_network_only_plugin( $plugin_file ) && ! is_plugin_active( $plugin_file ) ) {
     193                if ( $show_network_active ) {
     194                    // On the non-network screen, show inactive network-only plugins if allowed
     195                    $plugins['inactive'][ $plugin_file ] = $plugin_data;
     196                } else {
     197                    // On the non-network screen, filter out network-only plugins as long as they're not individually active
     198                    unset( $plugins['all'][ $plugin_file ] );
     199                }
     200            } elseif ( ! $screen->in_admin( 'network' ) && is_plugin_active_for_network( $plugin_file ) ) {
     201                if ( $show_network_active ) {
     202                    // On the non-network screen, show network-active plugins if allowed
     203                    $plugins['active'][ $plugin_file ] = $plugin_data;
     204                } else {
     205                    // On the non-network screen, filter out network-active plugins
     206                    unset( $plugins['all'][ $plugin_file ] );
     207                }
     208            } elseif ( ( ! $screen->in_admin( 'network' ) && is_plugin_active( $plugin_file ) )
     209                || ( $screen->in_admin( 'network' ) && is_plugin_active_for_network( $plugin_file ) ) ) {
     210                // On the non-network screen, populate the active list with plugins that are individually activated
     211                // On the network-admin screen, populate the active list with plugins that are network activated
     212                $plugins['active'][ $plugin_file ] = $plugin_data;
     213            } else {
     214                if ( isset( $recently_activated[ $plugin_file ] ) ) {
     215                    // Populate the recently activated list with plugins that have been recently activated
     216                    $plugins['recently_activated'][ $plugin_file ] = $plugin_data;
     217                }
     218                // Populate the inactive list with plugins that aren't activated
     219                $plugins['inactive'][ $plugin_file ] = $plugin_data;
     220            }
     221        }
     222
     223        if ( strlen( $s ) ) {
     224            $status = 'search';
     225            $plugins['search'] = array_filter( $plugins['all'], array( $this, '_search_callback' ) );
     226        }
     227
     228        $totals = array();
     229        foreach ( $plugins as $type => $list )
     230            $totals[ $type ] = count( $list );
     231
     232        if ( empty( $plugins[ $status ] ) && !in_array( $status, array( 'all', 'search' ) ) )
     233            $status = 'all';
     234
     235        $this->items = array();
     236        foreach ( $plugins[ $status ] as $plugin_file => $plugin_data ) {
     237            // Translate, Don't Apply Markup, Sanitize HTML
     238            $this->items[$plugin_file] = _get_plugin_data_markup_translate( $plugin_file, $plugin_data, false, true );
     239        }
     240
     241        $total_this_page = $totals[ $status ];
     242
     243        $js_plugins = array();
     244        foreach ( $plugins as $key => $list ) {
     245            $js_plugins[ $key ] = array_keys( (array) $list );
     246        }
     247
     248        wp_localize_script( 'updates', '_wpUpdatesItemCounts', array(
     249            'plugins' => $js_plugins,
     250            'totals'  => wp_get_update_data(),
     251        ) );
     252
     253        if ( ! $orderby ) {
     254            $orderby = 'Name';
     255        } else {
     256            $orderby = ucfirst( $orderby );
     257        }
     258
     259        $order = strtoupper( $order );
     260
     261        uasort( $this->items, array( $this, '_order_callback' ) );
     262
     263        $plugins_per_page = $this->get_items_per_page( str_replace( '-', '_', $screen->id . '_per_page' ), 999 );
     264
     265        $start = ( $page - 1 ) * $plugins_per_page;
     266
     267        if ( $total_this_page > $plugins_per_page )
     268            $this->items = array_slice( $this->items, $start, $plugins_per_page );
     269
     270        $this->set_pagination_args( array(
     271            'total_items' => $total_this_page,
     272            'per_page' => $plugins_per_page,
     273        ) );
     274    }
     275
     276    /**
     277     * @global string $s URL encoded search term.
     278     *
     279     * @param array $plugin
     280     * @return bool
     281     */
     282    public function _search_callback( $plugin ) {
     283        global $s;
     284
     285        foreach ( $plugin as $value ) {
     286            if ( is_string( $value ) && false !== stripos( strip_tags( $value ), urldecode( $s ) ) ) {
     287                return true;
     288            }
     289        }
     290
     291        return false;
     292    }
     293
     294    /**
     295     * @global string $orderby
     296     * @global string $order
     297     * @param array $plugin_a
     298     * @param array $plugin_b
     299     * @return int
     300     */
     301    public function _order_callback( $plugin_a, $plugin_b ) {
     302        global $orderby, $order;
     303
     304        $a = $plugin_a[$orderby];
     305        $b = $plugin_b[$orderby];
     306
     307        if ( $a == $b )
     308            return 0;
     309
     310        if ( 'DESC' === $order ) {
     311            return strcasecmp( $b, $a );
     312        } else {
     313            return strcasecmp( $a, $b );
     314        }
     315    }
     316
     317    /**
     318     *
     319     * @global array $plugins
     320     */
     321    public function no_items() {
     322        global $plugins;
     323
     324        if ( ! empty( $_REQUEST['s'] ) ) {
     325            $s = esc_html( wp_unslash( $_REQUEST['s'] ) );
     326
     327            printf( __( 'No plugins found for &#8220;%s&#8221;.' ), $s );
     328
     329            // We assume that somebody who can install plugins in multisite is experienced enough to not need this helper link.
     330            if ( ! is_multisite() && current_user_can( 'install_plugins' ) ) {
     331                echo ' <a href="' . esc_url( admin_url( 'plugin-install.php?tab=search&s=' . urlencode( $s ) ) ) . '">' . __( 'Search for plugins in the WordPress Plugin Directory.' ) . '</a>';
     332            }
     333        } elseif ( ! empty( $plugins['all'] ) )
     334            _e( 'No plugins found.' );
     335        else
     336            _e( 'You do not appear to have any plugins available at this time.' );
     337    }
     338
     339    /**
     340     * Displays the search box.
     341     *
     342     * @since 4.6.0
     343     * @access public
     344     *
     345     * @param string $text     The 'submit' button label.
     346     * @param string $input_id ID attribute value for the search input field.
     347     */
     348    public function search_box( $text, $input_id ) {
     349        if ( empty( $_REQUEST['s'] ) && ! $this->has_items() ) {
     350            return;
     351        }
     352
     353        $input_id = $input_id . '-search-input';
     354
     355        if ( ! empty( $_REQUEST['orderby'] ) ) {
     356            echo '<input type="hidden" name="orderby" value="' . esc_attr( $_REQUEST['orderby'] ) . '" />';
     357        }
     358        if ( ! empty( $_REQUEST['order'] ) ) {
     359            echo '<input type="hidden" name="order" value="' . esc_attr( $_REQUEST['order'] ) . '" />';
     360        }
     361        ?>
     362        <p class="search-box">
     363            <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>"><?php echo $text; ?>:</label>
     364            <input type="search" id="<?php echo esc_attr( $input_id ); ?>" class="wp-filter-search" name="s" value="<?php _admin_search_query(); ?>" placeholder="<?php esc_attr_e( 'Search installed plugins...' ); ?>"/>
     365            <?php submit_button( $text, 'hide-if-js', '', false, array( 'id' => 'search-submit' ) ); ?>
     366        </p>
     367        <?php
     368    }
     369
     370    /**
     371     *
     372     * @global string $status
     373     * @return array
     374     */
     375    public function get_columns() {
     376        global $status;
     377
     378        return array(
     379            'cb'          => !in_array( $status, array( 'mustuse', 'dropins' ) ) ? '<input type="checkbox" />' : '',
     380            'name'        => __( 'Plugin' ),
     381            'description' => __( 'Description' ),
     382        );
     383    }
     384
     385    /**
     386     * @return array
     387     */
     388    protected function get_sortable_columns() {
     389        return array();
     390    }
     391
     392    /**
     393     *
     394     * @global array $totals
     395     * @global string $status
     396     * @return array
     397     */
     398    protected function get_views() {
     399        global $totals, $status;
     400
     401        $status_links = array();
     402        foreach ( $totals as $type => $count ) {
     403            if ( !$count )
     404                continue;
     405
     406            switch ( $type ) {
     407                case 'all':
     408                    $text = _nx( 'All <span class="count">(%s)</span>', 'All <span class="count">(%s)</span>', $count, 'plugins' );
     409                    break;
     410                case 'active':
     411                    $text = _n( 'Active <span class="count">(%s)</span>', 'Active <span class="count">(%s)</span>', $count );
     412                    break;
     413                case 'recently_activated':
     414                    $text = _n( 'Recently Active <span class="count">(%s)</span>', 'Recently Active <span class="count">(%s)</span>', $count );
     415                    break;
     416                case 'inactive':
     417                    $text = _n( 'Inactive <span class="count">(%s)</span>', 'Inactive <span class="count">(%s)</span>', $count );
     418                    break;
     419                case 'mustuse':
     420                    $text = _n( 'Must-Use <span class="count">(%s)</span>', 'Must-Use <span class="count">(%s)</span>', $count );
     421                    break;
     422                case 'dropins':
     423                    $text = _n( 'Drop-ins <span class="count">(%s)</span>', 'Drop-ins <span class="count">(%s)</span>', $count );
     424                    break;
     425                case 'upgrade':
     426                    $text = _n( 'Update Available <span class="count">(%s)</span>', 'Update Available <span class="count">(%s)</span>', $count );
     427                    break;
     428            }
     429
     430            if ( 'search' !== $type ) {
     431                $status_links[$type] = sprintf( "<a href='%s' %s>%s</a>",
     432                    add_query_arg('plugin_status', $type, 'plugins.php'),
     433                    ( $type === $status ) ? ' class="current"' : '',
     434                    sprintf( $text, number_format_i18n( $count ) )
     435                    );
     436            }
     437        }
     438
     439        return $status_links;
     440    }
     441
     442    /**
     443     *
     444     * @global string $status
     445     * @return array
     446     */
     447    protected function get_bulk_actions() {
     448        global $status;
     449
     450        $actions = array();
     451
     452        if ( 'active' != $status )
     453            $actions['activate-selected'] = $this->screen->in_admin( 'network' ) ? __( 'Network Activate' ) : __( 'Activate' );
     454
     455        if ( 'inactive' != $status && 'recent' != $status )
     456            $actions['deactivate-selected'] = $this->screen->in_admin( 'network' ) ? __( 'Network Deactivate' ) : __( 'Deactivate' );
     457
     458        if ( !is_multisite() || $this->screen->in_admin( 'network' ) ) {
     459            if ( current_user_can( 'update_plugins' ) )
     460                $actions['update-selected'] = __( 'Update' );
     461            if ( current_user_can( 'delete_plugins' ) && ( 'active' != $status ) )
     462                $actions['delete-selected'] = __( 'Delete' );
     463        }
     464
     465        return $actions;
     466    }
     467
     468    /**
     469     * @global string $status
     470     * @param string $which
     471     */
     472    public function bulk_actions( $which = '' ) {
     473        global $status;
     474
     475        if ( in_array( $status, array( 'mustuse', 'dropins' ) ) )
     476            return;
     477
     478        parent::bulk_actions( $which );
     479    }
     480
     481    /**
     482     * @global string $status
     483     * @param string $which
     484     */
     485    protected function extra_tablenav( $which ) {
     486        global $status;
     487
     488        if ( ! in_array($status, array('recently_activated', 'mustuse', 'dropins') ) )
     489            return;
     490
     491        echo '<div class="alignleft actions">';
     492
     493        if ( 'recently_activated' == $status ) {
     494            submit_button( __( 'Clear List' ), '', 'clear-recent-list', false );
     495        } elseif ( 'top' === $which && 'mustuse' === $status ) {
     496            /* translators: %s: mu-plugins directory name */
     497            echo '<p>' . sprintf( __( 'Files in the %s directory are executed automatically.' ),
     498                '<code>' . str_replace( ABSPATH, '/', WPMU_PLUGIN_DIR ) . '</code>'
     499            ) . '</p>';
     500        } elseif ( 'top' === $which && 'dropins' === $status ) {
     501            /* translators: %s: wp-content directory name */
     502            echo '<p>' . sprintf( __( 'Drop-ins are advanced plugins in the %s directory that replace WordPress functionality when present.' ),
     503                '<code>' . str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '</code>'
     504            ) . '</p>';
     505        }
     506        echo '</div>';
     507    }
     508
     509    /**
     510     * @return string
     511     */
     512    public function current_action() {
     513        if ( isset($_POST['clear-recent-list']) )
     514            return 'clear-recent-list';
     515
     516        return parent::current_action();
     517    }
     518
     519    /**
     520     *
     521     * @global string $status
     522     */
     523    public function display_rows() {
     524        global $status;
     525
     526        if ( is_multisite() && ! $this->screen->in_admin( 'network' ) && in_array( $status, array( 'mustuse', 'dropins' ) ) )
     527            return;
     528
     529        foreach ( $this->items as $plugin_file => $plugin_data )
     530            $this->single_row( array( $plugin_file, $plugin_data ) );
     531    }
     532
     533    /**
     534     * @global string $status
     535     * @global int $page
     536     * @global string $s
     537     * @global array $totals
     538     *
     539     * @param array $item
     540     */
     541    public function single_row( $item ) {
     542        global $status, $page, $s, $totals;
     543
     544        list( $plugin_file, $plugin_data ) = $item;
     545        $context = $status;
     546        $screen = $this->screen;
     547
     548        // Pre-order.
     549        $actions = array(
     550            'deactivate' => '',
     551            'activate' => '',
     552            'details' => '',
     553            'edit' => '',
     554            'delete' => '',
     555        );
     556
     557        // Do not restrict by default
     558        $restrict_network_active = false;
     559        $restrict_network_only = false;
     560
     561        if ( 'mustuse' === $context ) {
     562            $is_active = true;
     563        } elseif ( 'dropins' === $context ) {
     564            $dropins = _get_dropins();
     565            $plugin_name = $plugin_file;
     566            if ( $plugin_file != $plugin_data['Name'] )
     567                $plugin_name .= '<br/>' . $plugin_data['Name'];
     568            if ( true === ( $dropins[ $plugin_file ][1] ) ) { // Doesn't require a constant
     569                $is_active = true;
     570                $description = '<p><strong>' . $dropins[ $plugin_file ][0] . '</strong></p>';
     571            } elseif ( defined( $dropins[ $plugin_file ][1] ) && constant( $dropins[ $plugin_file ][1] ) ) { // Constant is true
     572                $is_active = true;
     573                $description = '<p><strong>' . $dropins[ $plugin_file ][0] . '</strong></p>';
     574            } else {
     575                $is_active = false;
     576                $description = '<p><strong>' . $dropins[ $plugin_file ][0] . ' <span class="error-message">' . __( 'Inactive:' ) . '</span></strong> ' .
     577                    /* translators: 1: drop-in constant name, 2: wp-config.php */
     578                    sprintf( __( 'Requires %1$s in %2$s file.' ),
     579                        "<code>define('" . $dropins[ $plugin_file ][1] . "', true);</code>",
     580                        '<code>wp-config.php</code>'
     581                    ) . '</p>';
     582            }
     583            if ( $plugin_data['Description'] )
     584                $description .= '<p>' . $plugin_data['Description'] . '</p>';
     585        } else {
     586            if ( $screen->in_admin( 'network' ) ) {
     587                $is_active = is_plugin_active_for_network( $plugin_file );
     588            } else {
     589                $is_active = is_plugin_active( $plugin_file );
     590                $restrict_network_active = ( is_multisite() && is_plugin_active_for_network( $plugin_file ) );
     591                $restrict_network_only = ( is_multisite() && is_network_only_plugin( $plugin_file ) && ! $is_active );
     592            }
     593
     594            if ( $screen->in_admin( 'network' ) ) {
     595                if ( $is_active ) {
     596                    if ( current_user_can( 'manage_network_plugins' ) ) {
     597                        /* translators: %s: plugin name */
     598                        $actions['deactivate'] = '<a href="' . wp_nonce_url( 'plugins.php?action=deactivate&amp;plugin=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'deactivate-plugin_' . $plugin_file ) . '" aria-label="' . esc_attr( sprintf( _x( 'Network Deactivate %s', 'plugin' ), $plugin_data['Name'] ) ) . '">' . __( 'Network Deactivate' ) . '</a>';
     599                        }
     600                } else {
     601                    if ( current_user_can( 'manage_network_plugins' ) ) {
     602                        /* translators: %s: plugin name */
     603                        $actions['activate'] = '<a href="' . wp_nonce_url( 'plugins.php?action=activate&amp;plugin=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'activate-plugin_' . $plugin_file ) . '" class="edit" aria-label="' . esc_attr( sprintf( _x( 'Network Activate %s', 'plugin' ), $plugin_data['Name'] ) ) . '">' . __( 'Network Activate' ) . '</a>';
     604                    }
     605                    if ( current_user_can( 'delete_plugins' ) && ! is_plugin_active( $plugin_file ) ) {
     606                        /* translators: %s: plugin name */
     607                        $actions['delete'] = '<a href="' . wp_nonce_url( 'plugins.php?action=delete-selected&amp;checked[]=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'bulk-plugins' ) . '" class="delete" aria-label="' . esc_attr( sprintf( _x( 'Delete %s', 'plugin' ), $plugin_data['Name'] ) ) . '">' . __( 'Delete' ) . '</a>';
     608                    }
     609                }
     610            } else {
     611                if ( $restrict_network_active ) {
     612                    $actions = array(
     613                        'network_active' => __( 'Network Active' ),
     614                    );
     615                } elseif ( $restrict_network_only ) {
     616                    $actions = array(
     617                        'network_only' => __( 'Network Only' ),
     618                    );
     619                } elseif ( $is_active ) {
     620                    /* translators: %s: plugin name */
     621                    $actions['deactivate'] = '<a href="' . wp_nonce_url( 'plugins.php?action=deactivate&amp;plugin=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'deactivate-plugin_' . $plugin_file ) . '" aria-label="' . esc_attr( sprintf( _x( 'Deactivate %s', 'plugin' ), $plugin_data['Name'] ) ) . '">' . __( 'Deactivate' ) . '</a>';
     622                } else {
     623                    /* translators: %s: plugin name */
     624                    $actions['activate'] = '<a href="' . wp_nonce_url( 'plugins.php?action=activate&amp;plugin=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'activate-plugin_' . $plugin_file ) . '" class="edit" aria-label="' . esc_attr( sprintf( _x( 'Activate %s', 'plugin' ), $plugin_data['Name'] ) ) . '">' . __( 'Activate' ) . '</a>';
     625
     626                    if ( ! is_multisite() && current_user_can( 'delete_plugins' ) ) {
     627                        /* translators: %s: plugin name */
     628                        $actions['delete'] = '<a href="' . wp_nonce_url( 'plugins.php?action=delete-selected&amp;checked[]=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'bulk-plugins' ) . '" class="delete" aria-label="' . esc_attr( sprintf( _x( 'Delete %s', 'plugin' ), $plugin_data['Name'] ) ) . '">' . __( 'Delete' ) . '</a>';
     629                    }
     630                } // end if $is_active
     631
     632             } // end if $screen->in_admin( 'network' )
     633
     634            if ( ( ! is_multisite() || $screen->in_admin( 'network' ) ) && current_user_can( 'edit_plugins' ) && is_writable( WP_PLUGIN_DIR . '/' . $plugin_file ) ) {
     635                /* translators: %s: plugin name */
     636                $actions['edit'] = '<a href="plugin-editor.php?file=' . $plugin_file . '" class="edit" aria-label="' . esc_attr( sprintf( __( 'Edit %s' ), $plugin_data['Name'] ) ) . '">' . __( 'Edit' ) . '</a>';
     637            }
     638        } // end if $context
     639
     640        $actions = array_filter( $actions );
     641
     642        if ( $screen->in_admin( 'network' ) ) {
     643
     644            /**
     645             * Filters the action links displayed for each plugin in the Network Admin Plugins list table.
     646             *
     647             * The default action links for the Network plugins list table include
     648             * 'Network Activate', 'Network Deactivate', 'Edit', and 'Delete'.
     649             *
     650             * @since 3.1.0
     651             *
     652             * @param array  $actions     An array of plugin action links.
     653             * @param string $plugin_file Path to the plugin file relative to the plugins directory.
     654             * @param array  $plugin_data An array of plugin data.
     655             * @param string $context     The plugin context. Defaults are 'All', 'Active',
     656             *                            'Inactive', 'Recently Activated', 'Upgrade',
     657             *                            'Must-Use', 'Drop-ins', 'Search'.
     658             */
     659            $actions = apply_filters( 'network_admin_plugin_action_links', $actions, $plugin_file, $plugin_data, $context );
     660
     661            /**
     662             * Filters the list of action links displayed for a specific plugin in the Network Admin Plugins list table.
     663             *
     664             * The dynamic portion of the hook name, $plugin_file, refers to the path
     665             * to the plugin file, relative to the plugins directory.
     666             *
     667             * @since 3.1.0
     668             *
     669             * @param array  $actions     An array of plugin action links.
     670             * @param string $plugin_file Path to the plugin file relative to the plugins directory.
     671             * @param array  $plugin_data An array of plugin data.
     672             * @param string $context     The plugin context. Defaults are 'All', 'Active',
     673             *                            'Inactive', 'Recently Activated', 'Upgrade',
     674             *                            'Must-Use', 'Drop-ins', 'Search'.
     675             */
     676            $actions = apply_filters( "network_admin_plugin_action_links_{$plugin_file}", $actions, $plugin_file, $plugin_data, $context );
     677
     678        } else {
     679
     680            /**
     681             * Filters the action links displayed for each plugin in the Plugins list table.
     682             *
     683             * The default action links for the site plugins list table include
     684             * 'Activate', 'Deactivate', and 'Edit', for a network site, and
     685             * 'Activate', 'Deactivate', 'Edit', and 'Delete' for a single site.
     686             *
     687             * @since 2.5.0
     688             * @since 2.6.0 The `$context` parameter was added.
     689             *
     690             * @param array  $actions     An array of plugin action links.
     691             * @param string $plugin_file Path to the plugin file relative to the plugins directory.
     692             * @param array  $plugin_data An array of plugin data.
     693             * @param string $context     The plugin context. Defaults are 'All', 'Active',
     694             *                            'Inactive', 'Recently Activated', 'Upgrade',
     695             *                            'Must-Use', 'Drop-ins', 'Search'.
     696             */
     697            $actions = apply_filters( 'plugin_action_links', $actions, $plugin_file, $plugin_data, $context );
     698
     699            /**
     700             * Filters the list of action links displayed for a specific plugin in the Plugins list table.
     701             *
     702             * The dynamic portion of the hook name, $plugin_file, refers to the path
     703             * to the plugin file, relative to the plugins directory.
     704             *
     705             * @since 2.7.0
     706             *
     707             * @param array  $actions     An array of plugin action links.
     708             * @param string $plugin_file Path to the plugin file relative to the plugins directory.
     709             * @param array  $plugin_data An array of plugin data.
     710             * @param string $context     The plugin context. Defaults are 'All', 'Active',
     711             *                            'Inactive', 'Recently Activated', 'Upgrade',
     712             *                            'Must-Use', 'Drop-ins', 'Search'.
     713             */
     714            $actions = apply_filters( "plugin_action_links_{$plugin_file}", $actions, $plugin_file, $plugin_data, $context );
     715
     716        }
     717
     718        $class = $is_active ? 'active' : 'inactive';
     719        $checkbox_id =  "checkbox_" . md5($plugin_data['Name']);
     720        if ( $restrict_network_active || $restrict_network_only || in_array( $status, array( 'mustuse', 'dropins' ) ) ) {
     721            $checkbox = '';
     722        } else {
     723            $checkbox = "<label class='screen-reader-text' for='" . $checkbox_id . "' >" . sprintf( __( 'Select %s' ), $plugin_data['Name'] ) . "</label>"
     724                . "<input type='checkbox' name='checked[]' value='" . esc_attr( $plugin_file ) . "' id='" . $checkbox_id . "' />";
     725        }
     726        if ( 'dropins' != $context ) {
     727            $description = '<p>' . ( $plugin_data['Description'] ? $plugin_data['Description'] : '&nbsp;' ) . '</p>';
     728            $plugin_name = $plugin_data['Name'];
     729        }
     730
     731        if ( ! empty( $totals['upgrade'] ) && ! empty( $plugin_data['update'] ) )
     732            $class .= ' update';
     733
     734        $plugin_slug = isset( $plugin_data['slug'] ) ? $plugin_data['slug'] : sanitize_title( $plugin_name );
     735        printf( '<tr class="%s" data-slug="%s" data-plugin="%s">',
     736            esc_attr( $class ),
     737            esc_attr( $plugin_slug ),
     738            esc_attr( $plugin_file )
     739        );
     740
     741        list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
     742
     743        foreach ( $columns as $column_name => $column_display_name ) {
     744            $extra_classes = '';
     745            if ( in_array( $column_name, $hidden ) ) {
     746                $extra_classes = ' hidden';
     747            }
     748
     749            switch ( $column_name ) {
     750                case 'cb':
     751                    echo "<th scope='row' class='check-column'>$checkbox</th>";
     752                    break;
     753                case 'name':
     754                    echo "<td class='plugin-title column-primary'><strong>$plugin_name</strong>";
     755                    echo $this->row_actions( $actions, true );
     756                    echo "</td>";
     757                    break;
     758                case 'description':
     759                    $classes = 'column-description desc';
     760
     761                    echo "<td class='$classes{$extra_classes}'>
     762                        <div class='plugin-description'>$description</div>
     763                        <div class='$class second plugin-version-author-uri'>";
     764
     765                    $plugin_meta = array();
     766                    if ( !empty( $plugin_data['Version'] ) )
     767                        $plugin_meta[] = sprintf( __( 'Version %s' ), $plugin_data['Version'] );
     768                    if ( !empty( $plugin_data['Author'] ) ) {
     769                        $author = $plugin_data['Author'];
     770                        if ( !empty( $plugin_data['AuthorURI'] ) )
     771                            $author = '<a href="' . $plugin_data['AuthorURI'] . '">' . $plugin_data['Author'] . '</a>';
     772                        $plugin_meta[] = sprintf( __( 'By %s' ), $author );
     773                    }
     774
     775                    // Details link using API info, if available
     776                    if ( isset( $plugin_data['slug'] ) && current_user_can( 'install_plugins' ) ) {
     777                        $plugin_meta[] = sprintf( '<a href="%s" class="thickbox open-plugin-details-modal" aria-label="%s" data-title="%s">%s</a>',
     778                            esc_url( network_admin_url( 'plugin-install.php?tab=plugin-information&plugin=' . $plugin_data['slug'] .
     779                                '&TB_iframe=true&width=600&height=550' ) ),
     780                            esc_attr( sprintf( __( 'More information about %s' ), $plugin_name ) ),
     781                            esc_attr( $plugin_name ),
     782                            __( 'View details' )
     783                        );
     784                    } elseif ( ! empty( $plugin_data['PluginURI'] ) ) {
     785                        $plugin_meta[] = sprintf( '<a href="%s">%s</a>',
     786                            esc_url( $plugin_data['PluginURI'] ),
     787                            __( 'Visit plugin site' )
     788                        );
     789                    }
     790
     791                    /**
     792                     * Filters the array of row meta for each plugin in the Plugins list table.
     793                     *
     794                     * @since 2.8.0
     795                     *
     796                     * @param array  $plugin_meta An array of the plugin's metadata,
     797                     *                            including the version, author,
     798                     *                            author URI, and plugin URI.
     799                     * @param string $plugin_file Path to the plugin file, relative to the plugins directory.
     800                     * @param array  $plugin_data An array of plugin data.
     801                     * @param string $status      Status of the plugin. Defaults are 'All', 'Active',
     802                     *                            'Inactive', 'Recently Activated', 'Upgrade', 'Must-Use',
     803                     *                            'Drop-ins', 'Search'.
     804                     */
     805                    $plugin_meta = apply_filters( 'plugin_row_meta', $plugin_meta, $plugin_file, $plugin_data, $status );
     806                    echo implode( ' | ', $plugin_meta );
     807
     808                    echo "</div></td>";
     809                    break;
     810                default:
     811                    $classes = "$column_name column-$column_name $class";
     812
     813                    echo "<td class='$classes{$extra_classes}'>";
     814
     815                    /**
     816                     * Fires inside each custom column of the Plugins list table.
     817                     *
     818                     * @since 3.1.0
     819                     *
     820                     * @param string $column_name Name of the column.
     821                     * @param string $plugin_file Path to the plugin file.
     822                     * @param array  $plugin_data An array of plugin data.
     823                     */
     824                    do_action( 'manage_plugins_custom_column', $column_name, $plugin_file, $plugin_data );
     825
     826                    echo "</td>";
     827            }
     828        }
     829
     830        echo "</tr>";
     831
     832        /**
     833         * Fires after each row in the Plugins list table.
     834         *
     835         * @since 2.3.0
     836         *
     837         * @param string $plugin_file Path to the plugin file, relative to the plugins directory.
     838         * @param array  $plugin_data An array of plugin data.
     839         * @param string $status      Status of the plugin. Defaults are 'All', 'Active',
     840         *                            'Inactive', 'Recently Activated', 'Upgrade', 'Must-Use',
     841         *                            'Drop-ins', 'Search'.
     842         */
     843        do_action( 'after_plugin_row', $plugin_file, $plugin_data, $status );
     844
     845        /**
     846         * Fires after each specific row in the Plugins list table.
     847         *
     848         * The dynamic portion of the hook name, `$plugin_file`, refers to the path
     849         * to the plugin file, relative to the plugins directory.
     850         *
     851         * @since 2.7.0
     852         *
     853         * @param string $plugin_file Path to the plugin file, relative to the plugins directory.
     854         * @param array  $plugin_data An array of plugin data.
     855         * @param string $status      Status of the plugin. Defaults are 'All', 'Active',
     856         *                            'Inactive', 'Recently Activated', 'Upgrade', 'Must-Use',
     857         *                            'Drop-ins', 'Search'.
     858         */
     859        do_action( "after_plugin_row_{$plugin_file}", $plugin_file, $plugin_data, $status );
     860    }
     861
     862    /**
     863     * Gets the name of the primary column for this specific list table.
     864     *
     865     * @since 4.3.0
     866     * @access protected
     867     *
     868     * @return string Unalterable name for the primary column, in this case, 'name'.
     869     */
     870    protected function get_primary_column_name() {
     871        return 'name';
     872    }
    879873}
  • src/wp-admin/includes/class-wp-theme-install-list-table.php

    diff --git a/src/wp-admin/includes/class-wp-theme-install-list-table.php b/src/wp-admin/includes/class-wp-theme-install-list-table.php
    index f459d67d1c..7532056377 100644
    a b  
    1717 */
    1818class WP_Theme_Install_List_Table extends WP_Themes_List_Table {
    1919
    20         public $features = array();
    21 
    22         /**
    23          *
    24          * @return bool
    25          */
    26         public function ajax_user_can() {
    27                 return current_user_can( 'install_themes' );
    28         }
    29 
    30         /**
    31          *
    32          * @global array  $tabs
    33          * @global string $tab
    34          * @global int    $paged
    35          * @global string $type
    36          * @global array  $theme_field_defaults
    37          */
    38         public function prepare_items() {
    39                 include( ABSPATH . 'wp-admin/includes/theme-install.php' );
    40 
    41                 global $tabs, $tab, $paged, $type, $theme_field_defaults;
    42                 wp_reset_vars( array( 'tab' ) );
    43 
    44                 $search_terms = array();
    45                 $search_string = '';
    46                 if ( ! empty( $_REQUEST['s'] ) ){
    47                         $search_string = strtolower( wp_unslash( $_REQUEST['s'] ) );
    48                         $search_terms = array_unique( array_filter( array_map( 'trim', explode( ',', $search_string ) ) ) );
    49                 }
    50 
    51                 if ( ! empty( $_REQUEST['features'] ) )
    52                         $this->features = $_REQUEST['features'];
    53 
    54                 $paged = $this->get_pagenum();
    55 
    56                 $per_page = 36;
    57 
    58                 // These are the tabs which are shown on the page,
    59                 $tabs = array();
    60                 $tabs['dashboard'] = __( 'Search' );
    61                 if ( 'search' === $tab )
    62                         $tabs['search'] = __( 'Search Results' );
    63                 $tabs['upload'] = __( 'Upload' );
    64                 $tabs['featured'] = _x( 'Featured', 'themes' );
    65                 //$tabs['popular']  = _x( 'Popular', 'themes' );
    66                 $tabs['new']      = _x( 'Latest', 'themes' );
    67                 $tabs['updated']  = _x( 'Recently Updated', 'themes' );
    68 
    69                 $nonmenu_tabs = array( 'theme-information' ); // Valid actions to perform which do not have a Menu item.
    70 
    71                 /** This filter is documented in wp-admin/theme-install.php */
    72                 $tabs = apply_filters( 'install_themes_tabs', $tabs );
    73 
    74                 /**
    75                  * Filters tabs not associated with a menu item on the Install Themes screen.
    76                  *
    77                  * @since 2.8.0
    78                  *
    79                  * @param array $nonmenu_tabs The tabs that don't have a menu item on
    80                  *                            the Install Themes screen.
    81                  */
    82                 $nonmenu_tabs = apply_filters( 'install_themes_nonmenu_tabs', $nonmenu_tabs );
    83 
    84                 // If a non-valid menu tab has been selected, And it's not a non-menu action.
    85                 if ( empty( $tab ) || ( ! isset( $tabs[ $tab ] ) && ! in_array( $tab, (array) $nonmenu_tabs ) ) )
    86                         $tab = key( $tabs );
    87 
    88                 $args = array( 'page' => $paged, 'per_page' => $per_page, 'fields' => $theme_field_defaults );
    89 
    90                 switch ( $tab ) {
    91                         case 'search':
    92                                 $type = isset( $_REQUEST['type'] ) ? wp_unslash( $_REQUEST['type'] ) : 'term';
    93                                 switch ( $type ) {
    94                                         case 'tag':
    95                                                 $args['tag'] = array_map( 'sanitize_key', $search_terms );
    96                                                 break;
    97                                         case 'term':
    98                                                 $args['search'] = $search_string;
    99                                                 break;
    100                                         case 'author':
    101                                                 $args['author'] = $search_string;
    102                                                 break;
    103                                 }
    104 
    105                                 if ( ! empty( $this->features ) ) {
    106                                         $args['tag'] = $this->features;
    107                                         $_REQUEST['s'] = implode( ',', $this->features );
    108                                         $_REQUEST['type'] = 'tag';
    109                                 }
    110 
    111                                 add_action( 'install_themes_table_header', 'install_theme_search_form', 10, 0 );
    112                                 break;
    113 
    114                         case 'featured':
    115                         // case 'popular':
    116                         case 'new':
    117                         case 'updated':
    118                                 $args['browse'] = $tab;
    119                                 break;
    120 
    121                         default:
    122                                 $args = false;
    123                                 break;
    124                 }
    125 
    126                 /**
    127                  * Filters API request arguments for each Install Themes screen tab.
    128                  *
    129                  * The dynamic portion of the hook name, `$tab`, refers to the theme install
    130                  * tabs. Default tabs are 'dashboard', 'search', 'upload', 'featured',
    131                  * 'new', and 'updated'.
    132                  *
    133                  * @since 3.7.0
    134                  *
    135                  * @param array $args An array of themes API arguments.
    136                  */
    137                 $args = apply_filters( "install_themes_table_api_args_{$tab}", $args );
    138 
    139                 if ( ! $args )
    140                         return;
    141 
    142                 $api = themes_api( 'query_themes', $args );
    143 
    144                 if ( is_wp_error( $api ) )
    145                         wp_die( $api->get_error_message() . '</p> <p><a href="#" onclick="document.location.reload(); return false;">' . __( 'Try again' ) . '</a>' );
    146 
    147                 $this->items = $api->themes;
    148 
    149                 $this->set_pagination_args( array(
    150                         'total_items' => $api->info['results'],
    151                         'per_page' => $args['per_page'],
    152                         'infinite_scroll' => true,
    153                 ) );
    154         }
    155 
    156         /**
    157          * @access public
    158          */
    159         public function no_items() {
    160                 _e( 'No themes match your request.' );
    161         }
    162 
    163         /**
    164          *
    165          * @global array $tabs
    166          * @global string $tab
    167          * @return array
    168          */
    169         protected function get_views() {
    170                 global $tabs, $tab;
    171 
    172                 $display_tabs = array();
    173                 foreach ( (array) $tabs as $action => $text ) {
    174                         $class = ( $action === $tab ) ? ' class="current"' : '';
    175                         $href = self_admin_url('theme-install.php?tab=' . $action);
    176                         $display_tabs['theme-install-'.$action] = "<a href='$href'$class>$text</a>";
    177                 }
    178 
    179                 return $display_tabs;
    180         }
    181 
    182         /**
    183          * @access public
    184          */
    185         public function display() {
    186                 wp_nonce_field( "fetch-list-" . get_class( $this ), '_ajax_fetch_list_nonce' );
     20    public $features = array();
     21
     22    /**
     23     *
     24     * @return bool
     25     */
     26    public function ajax_user_can() {
     27        return current_user_can( 'install_themes' );
     28    }
     29
     30    public function prepare_items() {
     31        include( ABSPATH . 'wp-admin/includes/theme-install.php' );
     32
     33        $tab = wp_assign_request_var('tab');
     34        $type = wp_assign_request_var('type');
     35        $term = wp_assign_request_var('term');
     36        $theme_field_defaults = wp_assign_request_var('theme_field_defaults');
     37
     38        $search_terms = array();
     39        $search_string = '';
     40        if ( ! empty( $_REQUEST['s'] ) ){
     41            $search_string = strtolower( wp_unslash( $_REQUEST['s'] ) );
     42            $search_terms = array_unique( array_filter( array_map( 'trim', explode( ',', $search_string ) ) ) );
     43        }
     44
     45        if ( ! empty( $_REQUEST['features'] ) )
     46            $this->features = $_REQUEST['features'];
     47
     48        $paged = $this->get_pagenum();
     49
     50        $per_page = 36;
     51
     52        // These are the tabs which are shown on the page,
     53        $tabs = array();
     54        $tabs['dashboard'] = __( 'Search' );
     55        if ( 'search' === $tab )
     56            $tabs['search']     = __( 'Search Results' );
     57        $tabs['upload'] = __( 'Upload' );
     58        $tabs['featured'] = _x( 'Featured', 'themes' );
     59        //$tabs['popular']  = _x( 'Popular', 'themes' );
     60        $tabs['new']      = _x( 'Latest', 'themes' );
     61        $tabs['updated']  = _x( 'Recently Updated', 'themes' );
     62
     63        $nonmenu_tabs = array( 'theme-information' ); // Valid actions to perform which do not have a Menu item.
     64
     65        /** This filter is documented in wp-admin/theme-install.php */
     66        $tabs = apply_filters( 'install_themes_tabs', $tabs );
     67
     68        /**
     69         * Filters tabs not associated with a menu item on the Install Themes screen.
     70         *
     71         * @since 2.8.0
     72         *
     73         * @param array $nonmenu_tabs The tabs that don't have a menu item on
     74         *                            the Install Themes screen.
     75         */
     76        $nonmenu_tabs = apply_filters( 'install_themes_nonmenu_tabs', $nonmenu_tabs );
     77
     78        // If a non-valid menu tab has been selected, And it's not a non-menu action.
     79        if ( empty( $tab ) || ( ! isset( $tabs[ $tab ] ) && ! in_array( $tab, (array) $nonmenu_tabs ) ) )
     80            $tab = key( $tabs );
     81
     82        $args = array( 'page' => $paged, 'per_page' => $per_page, 'fields' => $theme_field_defaults );
     83
     84        switch ( $tab ) {
     85            case 'search':
     86                $type = isset( $_REQUEST['type'] ) ? wp_unslash( $_REQUEST['type'] ) : 'term';
     87                switch ( $type ) {
     88                    case 'tag':
     89                        $args['tag'] = array_map( 'sanitize_key', $search_terms );
     90                        break;
     91                    case 'term':
     92                        $args['search'] = $search_string;
     93                        break;
     94                    case 'author':
     95                        $args['author'] = $search_string;
     96                        break;
     97                }
     98
     99                if ( ! empty( $this->features ) ) {
     100                    $args['tag'] = $this->features;
     101                    $_REQUEST['s'] = implode( ',', $this->features );
     102                    $_REQUEST['type'] = 'tag';
     103                }
     104
     105                add_action( 'install_themes_table_header', 'install_theme_search_form', 10, 0 );
     106                break;
     107
     108            case 'featured':
     109            // case 'popular':
     110            case 'new':
     111            case 'updated':
     112                $args['browse'] = $tab;
     113                break;
     114
     115            default:
     116                $args = false;
     117                break;
     118        }
     119
     120        /**
     121         * Filters API request arguments for each Install Themes screen tab.
     122         *
     123         * The dynamic portion of the hook name, `$tab`, refers to the theme install
     124         * tabs. Default tabs are 'dashboard', 'search', 'upload', 'featured',
     125         * 'new', and 'updated'.
     126         *
     127         * @since 3.7.0
     128         *
     129         * @param array $args An array of themes API arguments.
     130         */
     131        $args = apply_filters( "install_themes_table_api_args_{$tab}", $args );
     132
     133        if ( ! $args )
     134            return;
     135
     136        $api = themes_api( 'query_themes', $args );
     137
     138        if ( is_wp_error( $api ) )
     139            wp_die( $api->get_error_message() . '</p> <p><a href="#" onclick="document.location.reload(); return false;">' . __( 'Try again' ) . '</a>' );
     140
     141        $this->items = $api->themes;
     142
     143        $this->set_pagination_args( array(
     144            'total_items' => $api->info['results'],
     145            'per_page' => $args['per_page'],
     146            'infinite_scroll' => true,
     147        ) );
     148    }
     149
     150    /**
     151     * @access public
     152     */
     153    public function no_items() {
     154        _e( 'No themes match your request.' );
     155    }
     156
     157    /**
     158     *
     159     * @global array $tabs
     160     * @global string $tab
     161     * @return array
     162     */
     163    protected function get_views() {
     164        global $tabs, $tab;
     165
     166        $display_tabs = array();
     167        foreach ( (array) $tabs as $action => $text ) {
     168            $class = ( $action === $tab ) ? ' class="current"' : '';
     169            $href = self_admin_url('theme-install.php?tab=' . $action);
     170            $display_tabs['theme-install-'.$action] = "<a href='$href'$class>$text</a>";
     171        }
     172
     173        return $display_tabs;
     174    }
     175
     176    /**
     177     * @access public
     178     */
     179    public function display() {
     180        wp_nonce_field( "fetch-list-" . get_class( $this ), '_ajax_fetch_list_nonce' );
    187181?>
    188                 <div class="tablenav top themes">
    189                         <div class="alignleft actions">
    190                                 <?php
    191                                 /**
    192                                 * Fires in the Install Themes list table header.
    193                                 *
    194                                 * @since 2.8.0
    195                                 */
    196                                 do_action( 'install_themes_table_header' );
    197                                 ?>
    198                         </div>
    199                         <?php $this->pagination( 'top' ); ?>
    200                         <br class="clear" />
    201                 </div>
    202 
    203                 <div id="availablethemes">
    204                         <?php $this->display_rows_or_placeholder(); ?>
    205                 </div>
    206 
    207                 <?php
    208                 $this->tablenav( 'bottom' );
    209         }
    210 
    211         /**
    212         * @access public
    213         */
    214         public function display_rows() {
    215                 $themes = $this->items;
    216                 foreach ( $themes as $theme ) {
    217                                 ?>
    218                                 <div class="available-theme installable-theme"><?php
    219                                         $this->single_row( $theme );
    220                                 ?></div>
    221                 <?php } // end foreach $theme_names
    222 
    223                 $this->theme_installer();
    224         }
    225 
    226         /**
    227         * Prints a theme from the WordPress.org API.
    228         *
    229         * @since 3.1.0
    230         * @access public
    231         *
    232         * @global array $themes_allowedtags
    233         *
    234         * @param object $theme {
    235         *     An object that contains theme data returned by the WordPress.org API.
    236         *
    237         *     @type string $name           Theme name, e.g. 'Twenty Seventeen'.
    238         *     @type string $slug           Theme slug, e.g. 'twentyseventeen'.
    239         *     @type string $version        Theme version, e.g. '1.1'.
    240         *     @type string $author         Theme author username, e.g. 'melchoyce'.
    241         *     @type string $preview_url    Preview URL, e.g. 'http://2017.wordpress.net/'.
    242         *     @type string $screenshot_url Screenshot URL, e.g. 'https://wordpress.org/themes/twentyseventeen/'.
    243         *     @type float  $rating         Rating score.
    244         *     @type int    $num_ratings    The number of ratings.
    245         *     @type string $homepage       Theme homepage, e.g. 'https://wordpress.org/themes/twentyseventeen/'.
    246         *     @type string $description    Theme description.
    247         *     @type string $download_link  Theme ZIP download URL.
    248         * }
    249         */
    250         public function single_row( $theme ) {
    251                 global $themes_allowedtags;
    252 
    253                 if ( empty( $theme ) )
    254                         return;
    255 
    256                 $name   = wp_kses( $theme->name,   $themes_allowedtags );
    257                 $author = wp_kses( $theme->author, $themes_allowedtags );
    258 
    259                 $preview_title = sprintf( __('Preview &#8220;%s&#8221;'), $name );
    260                 $preview_url   = add_query_arg( array(
    261                         'tab'   => 'theme-information',
    262                         'theme' => $theme->slug,
    263                 ), self_admin_url( 'theme-install.php' ) );
    264 
    265                 $actions = array();
    266 
    267                 $install_url = add_query_arg( array(
    268                         'action' => 'install-theme',
    269                         'theme'  => $theme->slug,
    270                 ), self_admin_url( 'update.php' ) );
    271 
    272                 $update_url = add_query_arg( array(
    273                         'action' => 'upgrade-theme',
    274                         'theme'  => $theme->slug,
    275                 ), self_admin_url( 'update.php' ) );
    276 
    277                 $status = $this->_get_theme_status( $theme );
    278 
    279                 switch ( $status ) {
    280                         case 'update_available':
    281                                 $actions[] = '<a class="install-now" href="' . esc_url( wp_nonce_url( $update_url, 'upgrade-theme_' . $theme->slug ) ) . '" title="' . esc_attr( sprintf( __( 'Update to version %s' ), $theme->version ) ) . '">' . __( 'Update' ) . '</a>';
    282                                 break;
    283                         case 'newer_installed':
    284                         case 'latest_installed':
    285                                 $actions[] = '<span class="install-now" title="' . esc_attr__( 'This theme is already installed and is up to date' ) . '">' . _x( 'Installed', 'theme' ) . '</span>';
    286                                 break;
    287                         case 'install':
    288                         default:
    289                                 $actions[] = '<a class="install-now" href="' . esc_url( wp_nonce_url( $install_url, 'install-theme_' . $theme->slug ) ) . '" title="' . esc_attr( sprintf( __( 'Install %s' ), $name ) ) . '">' . __( 'Install Now' ) . '</a>';
    290                                 break;
    291                 }
    292 
    293                 $actions[] = '<a class="install-theme-preview" href="' . esc_url( $preview_url ) . '" title="' . esc_attr( sprintf( __( 'Preview %s' ), $name ) ) . '">' . __( 'Preview' ) . '</a>';
    294 
    295                 /**
    296                 * Filters the install action links for a theme in the Install Themes list table.
    297                 *
    298                 * @since 3.4.0
    299                 *
    300                 * @param array    $actions An array of theme action hyperlinks. Defaults are
    301                 *                          links to Install Now, Preview, and Details.
    302                 * @param WP_Theme $theme   Theme object.
    303                 */
    304                 $actions = apply_filters( 'theme_install_actions', $actions, $theme );
    305 
    306                 ?>
    307                 <a class="screenshot install-theme-preview" href="<?php echo esc_url( $preview_url ); ?>" title="<?php echo esc_attr( $preview_title ); ?>">
    308                         <img src="<?php echo esc_url( $theme->screenshot_url ); ?>" width="150" alt="" />
    309                 </a>
    310 
    311                 <h3><?php echo $name; ?></h3>
    312                 <div class="theme-author"><?php printf( __( 'By %s' ), $author ); ?></div>
    313 
    314                 <div class="action-links">
    315                         <ul>
    316                                 <?php foreach ( $actions as $action ): ?>
    317                                         <li><?php echo $action; ?></li>
    318                                 <?php endforeach; ?>
    319                                 <li class="hide-if-no-js"><a href="#" class="theme-detail"><?php _e('Details') ?></a></li>
    320                         </ul>
    321                 </div>
    322 
    323                 <?php
    324                 $this->install_theme_info( $theme );
    325         }
    326 
    327         /**
    328         * Prints the wrapper for the theme installer.
    329         */
    330         public function theme_installer() {
    331                 ?>
    332                 <div id="theme-installer" class="wp-full-overlay expanded">
    333                         <div class="wp-full-overlay-sidebar">
    334                                 <div class="wp-full-overlay-header">
    335                                         <a href="#" class="close-full-overlay button"><?php _e( 'Close' ); ?></a>
    336                                         <span class="theme-install"></span>
    337                                 </div>
    338                                 <div class="wp-full-overlay-sidebar-content">
    339                                         <div class="install-theme-info"></div>
    340                                 </div>
    341                                 <div class="wp-full-overlay-footer">
    342                                         <button type="button" class="collapse-sidebar button" aria-expanded="true" aria-label="<?php esc_attr_e( 'Collapse Sidebar' ); ?>">
    343                                                 <span class="collapse-sidebar-arrow"></span>
    344                                                 <span class="collapse-sidebar-label"><?php _e( 'Collapse' ); ?></span>
    345                                         </button>
    346                                 </div>
    347                         </div>
    348                         <div class="wp-full-overlay-main"></div>
    349                 </div>
    350                 <?php
    351         }
    352 
    353         /**
    354         * Prints the wrapper for the theme installer with a provided theme's data.
    355         * Used to make the theme installer work for no-js.
    356         *
    357         * @param object $theme - A WordPress.org Theme API object.
    358         */
    359         public function theme_installer_single( $theme ) {
    360                 ?>
    361                 <div id="theme-installer" class="wp-full-overlay single-theme">
    362                         <div class="wp-full-overlay-sidebar">
    363                                 <?php $this->install_theme_info( $theme ); ?>
    364                         </div>
    365                         <div class="wp-full-overlay-main">
    366                                 <iframe src="<?php echo esc_url( $theme->preview_url ); ?>"></iframe>
    367                         </div>
    368                 </div>
    369                 <?php
    370         }
    371 
    372         /**
    373         * Prints the info for a theme (to be used in the theme installer modal).
    374         *
    375         * @global array $themes_allowedtags
    376         *
    377         * @param object $theme - A WordPress.org Theme API object.
    378         */
    379         public function install_theme_info( $theme ) {
    380                 global $themes_allowedtags;
    381 
    382                 if ( empty( $theme ) )
    383                         return;
    384 
    385                 $name   = wp_kses( $theme->name,   $themes_allowedtags );
    386                 $author = wp_kses( $theme->author, $themes_allowedtags );
    387 
    388                 $install_url = add_query_arg( array(
    389                         'action' => 'install-theme',
    390                         'theme'  => $theme->slug,
    391                 ), self_admin_url( 'update.php' ) );
    392 
    393                 $update_url = add_query_arg( array(
    394                         'action' => 'upgrade-theme',
    395                         'theme'  => $theme->slug,
    396                 ), self_admin_url( 'update.php' ) );
    397 
    398                 $status = $this->_get_theme_status( $theme );
    399 
    400                 ?>
    401                 <div class="install-theme-info"><?php
    402                         switch ( $status ) {
    403                                 case 'update_available':
    404                                         echo '<a class="theme-install button button-primary" href="' . esc_url( wp_nonce_url( $update_url, 'upgrade-theme_' . $theme->slug ) ) . '" title="' . esc_attr( sprintf( __( 'Update to version %s' ), $theme->version ) ) . '">' . __( 'Update' ) . '</a>';
    405                                         break;
    406                                 case 'newer_installed':
    407                                 case 'latest_installed':
    408                                         echo '<span class="theme-install" title="' . esc_attr__( 'This theme is already installed and is up to date' ) . '">' . _x( 'Installed', 'theme' ) . '</span>';
    409                                         break;
    410                                 case 'install':
    411                                 default:
    412                                         echo '<a class="theme-install button button-primary" href="' . esc_url( wp_nonce_url( $install_url, 'install-theme_' . $theme->slug ) ) . '">' . __( 'Install' ) . '</a>';
    413                                         break;
    414                         } ?>
    415                         <h3 class="theme-name"><?php echo $name; ?></h3>
    416                         <span class="theme-by"><?php printf( __( 'By %s' ), $author ); ?></span>
    417                         <?php if ( isset( $theme->screenshot_url ) ): ?>
    418                                 <img class="theme-screenshot" src="<?php echo esc_url( $theme->screenshot_url ); ?>" alt="" />
    419                         <?php endif; ?>
    420                         <div class="theme-details">
    421                                 <?php wp_star_rating( array( 'rating' => $theme->rating, 'type' => 'percent', 'number' => $theme->num_ratings ) ); ?>
    422                                 <div class="theme-version">
    423                                         <strong><?php _e('Version:') ?> </strong>
    424                                         <?php echo wp_kses( $theme->version, $themes_allowedtags ); ?>
    425                                 </div>
    426                                 <div class="theme-description">
    427                                         <?php echo wp_kses( $theme->description, $themes_allowedtags ); ?>
    428                                 </div>
    429                         </div>
    430                         <input class="theme-preview-url" type="hidden" value="<?php echo esc_url( $theme->preview_url ); ?>" />
    431                 </div>
    432                 <?php
    433         }
    434 
    435         /**
    436         * Send required variables to JavaScript land
    437         *
    438         * @since 3.4.0
    439         * @access public
    440         *
    441         * @global string $tab  Current tab within Themes->Install screen
    442         * @global string $type Type of search.
    443         *
    444         * @param array $extra_args Unused.
    445         */
    446         public function _js_vars( $extra_args = array() ) {
    447                 global $tab, $type;
    448                 parent::_js_vars( compact( 'tab', 'type' ) );
    449         }
    450 
    451         /**
    452         * Check to see if the theme is already installed.
    453         *
    454         * @since 3.4.0
    455         * @access private
    456         *
    457         * @param object $theme - A WordPress.org Theme API object.
    458         * @return string Theme status.
    459         */
    460         private function _get_theme_status( $theme ) {
    461                 $status = 'install';
    462 
    463                 $installed_theme = wp_get_theme( $theme->slug );
    464                 if ( $installed_theme->exists() ) {
    465                         if ( version_compare( $installed_theme->get('Version'), $theme->version, '=' ) )
    466                                 $status = 'latest_installed';
    467                         elseif ( version_compare( $installed_theme->get('Version'), $theme->version, '>' ) )
    468                                 $status = 'newer_installed';
    469                         else
    470                                 $status = 'update_available';
    471                 }
    472 
    473                 return $status;
    474         }
     182        <div class="tablenav top themes">
     183            <div class="alignleft actions">
     184                <?php
     185                /**
     186                * Fires in the Install Themes list table header.
     187                *
     188                * @since 2.8.0
     189                */
     190                do_action( 'install_themes_table_header' );
     191                ?>
     192            </div>
     193            <?php $this->pagination( 'top' ); ?>
     194            <br class="clear" />
     195        </div>
     196
     197        <div id="availablethemes">
     198            <?php $this->display_rows_or_placeholder(); ?>
     199        </div>
     200
     201        <?php
     202        $this->tablenav( 'bottom' );
     203    }
     204
     205    /**
     206    * @access public
     207    */
     208    public function display_rows() {
     209        $themes = $this->items;
     210        foreach ( $themes as $theme ) {
     211                ?>
     212                <div class="available-theme installable-theme"><?php
     213                    $this->single_row( $theme );
     214                ?></div>
     215        <?php } // end foreach $theme_names
     216
     217        $this->theme_installer();
     218    }
     219
     220    /**
     221    * Prints a theme from the WordPress.org API.
     222    *
     223    * @since 3.1.0
     224    * @access public
     225    *
     226    * @global array $themes_allowedtags
     227    *
     228    * @param object $theme {
     229    *     An object that contains theme data returned by the WordPress.org API.
     230    *
     231    *     @type string $name           Theme name, e.g. 'Twenty Seventeen'.
     232    *     @type string $slug           Theme slug, e.g. 'twentyseventeen'.
     233    *     @type string $version        Theme version, e.g. '1.1'.
     234    *     @type string $author         Theme author username, e.g. 'melchoyce'.
     235    *     @type string $preview_url    Preview URL, e.g. 'http://2017.wordpress.net/'.
     236    *     @type string $screenshot_url Screenshot URL, e.g. 'https://wordpress.org/themes/twentyseventeen/'.
     237    *     @type float  $rating         Rating score.
     238    *     @type int    $num_ratings    The number of ratings.
     239    *     @type string $homepage       Theme homepage, e.g. 'https://wordpress.org/themes/twentyseventeen/'.
     240    *     @type string $description    Theme description.
     241    *     @type string $download_link  Theme ZIP download URL.
     242    * }
     243    */
     244    public function single_row( $theme ) {
     245        global $themes_allowedtags;
     246
     247        if ( empty( $theme ) )
     248            return;
     249
     250        $name   = wp_kses( $theme->name,   $themes_allowedtags );
     251        $author = wp_kses( $theme->author, $themes_allowedtags );
     252
     253        $preview_title = sprintf( __('Preview &#8220;%s&#8221;'), $name );
     254        $preview_url   = add_query_arg( array(
     255            'tab'   => 'theme-information',
     256            'theme' => $theme->slug,
     257        ), self_admin_url( 'theme-install.php' ) );
     258
     259        $actions = array();
     260
     261        $install_url = add_query_arg( array(
     262            'action' => 'install-theme',
     263            'theme'  => $theme->slug,
     264        ), self_admin_url( 'update.php' ) );
     265
     266        $update_url = add_query_arg( array(
     267            'action' => 'upgrade-theme',
     268            'theme'  => $theme->slug,
     269        ), self_admin_url( 'update.php' ) );
     270
     271        $status = $this->_get_theme_status( $theme );
     272
     273        switch ( $status ) {
     274            case 'update_available':
     275                $actions[] = '<a class="install-now" href="' . esc_url( wp_nonce_url( $update_url, 'upgrade-theme_' . $theme->slug ) ) . '" title="' . esc_attr( sprintf( __( 'Update to version %s' ), $theme->version ) ) . '">' . __( 'Update' ) . '</a>';
     276                break;
     277            case 'newer_installed':
     278            case 'latest_installed':
     279                $actions[] = '<span class="install-now" title="' . esc_attr__( 'This theme is already installed and is up to date' ) . '">' . _x( 'Installed', 'theme' ) . '</span>';
     280                break;
     281            case 'install':
     282            default:
     283                $actions[] = '<a class="install-now" href="' . esc_url( wp_nonce_url( $install_url, 'install-theme_' . $theme->slug ) ) . '" title="' . esc_attr( sprintf( __( 'Install %s' ), $name ) ) . '">' . __( 'Install Now' ) . '</a>';
     284                break;
     285        }
     286
     287        $actions[] = '<a class="install-theme-preview" href="' . esc_url( $preview_url ) . '" title="' . esc_attr( sprintf( __( 'Preview %s' ), $name ) ) . '">' . __( 'Preview' ) . '</a>';
     288
     289        /**
     290        * Filters the install action links for a theme in the Install Themes list table.
     291        *
     292        * @since 3.4.0
     293        *
     294        * @param array    $actions An array of theme action hyperlinks. Defaults are
     295        *                          links to Install Now, Preview, and Details.
     296        * @param WP_Theme $theme   Theme object.
     297        */
     298        $actions = apply_filters( 'theme_install_actions', $actions, $theme );
     299
     300        ?>
     301        <a class="screenshot install-theme-preview" href="<?php echo esc_url( $preview_url ); ?>" title="<?php echo esc_attr( $preview_title ); ?>">
     302            <img src="<?php echo esc_url( $theme->screenshot_url ); ?>" width="150" alt="" />
     303        </a>
     304
     305        <h3><?php echo $name; ?></h3>
     306        <div class="theme-author"><?php printf( __( 'By %s' ), $author ); ?></div>
     307
     308        <div class="action-links">
     309            <ul>
     310                <?php foreach ( $actions as $action ): ?>
     311                    <li><?php echo $action; ?></li>
     312                <?php endforeach; ?>
     313                <li class="hide-if-no-js"><a href="#" class="theme-detail"><?php _e('Details') ?></a></li>
     314            </ul>
     315        </div>
     316
     317        <?php
     318        $this->install_theme_info( $theme );
     319    }
     320
     321    /**
     322    * Prints the wrapper for the theme installer.
     323    */
     324    public function theme_installer() {
     325        ?>
     326        <div id="theme-installer" class="wp-full-overlay expanded">
     327            <div class="wp-full-overlay-sidebar">
     328                <div class="wp-full-overlay-header">
     329                    <a href="#" class="close-full-overlay button"><?php _e( 'Close' ); ?></a>
     330                    <span class="theme-install"></span>
     331                </div>
     332                <div class="wp-full-overlay-sidebar-content">
     333                    <div class="install-theme-info"></div>
     334                </div>
     335                <div class="wp-full-overlay-footer">
     336                    <button type="button" class="collapse-sidebar button" aria-expanded="true" aria-label="<?php esc_attr_e( 'Collapse Sidebar' ); ?>">
     337                        <span class="collapse-sidebar-arrow"></span>
     338                        <span class="collapse-sidebar-label"><?php _e( 'Collapse' ); ?></span>
     339                    </button>
     340                </div>
     341            </div>
     342            <div class="wp-full-overlay-main"></div>
     343        </div>
     344        <?php
     345    }
     346
     347    /**
     348    * Prints the wrapper for the theme installer with a provided theme's data.
     349    * Used to make the theme installer work for no-js.
     350    *
     351    * @param object $theme - A WordPress.org Theme API object.
     352    */
     353    public function theme_installer_single( $theme ) {
     354        ?>
     355        <div id="theme-installer" class="wp-full-overlay single-theme">
     356            <div class="wp-full-overlay-sidebar">
     357                <?php $this->install_theme_info( $theme ); ?>
     358            </div>
     359            <div class="wp-full-overlay-main">
     360                <iframe src="<?php echo esc_url( $theme->preview_url ); ?>"></iframe>
     361            </div>
     362        </div>
     363        <?php
     364    }
     365
     366    /**
     367    * Prints the info for a theme (to be used in the theme installer modal).
     368    *
     369    * @global array $themes_allowedtags
     370    *
     371    * @param object $theme - A WordPress.org Theme API object.
     372    */
     373    public function install_theme_info( $theme ) {
     374        global $themes_allowedtags;
     375
     376        if ( empty( $theme ) )
     377            return;
     378
     379        $name   = wp_kses( $theme->name,   $themes_allowedtags );
     380        $author = wp_kses( $theme->author, $themes_allowedtags );
     381
     382        $install_url = add_query_arg( array(
     383            'action' => 'install-theme',
     384            'theme'  => $theme->slug,
     385        ), self_admin_url( 'update.php' ) );
     386
     387        $update_url = add_query_arg( array(
     388            'action' => 'upgrade-theme',
     389            'theme'  => $theme->slug,
     390        ), self_admin_url( 'update.php' ) );
     391
     392        $status = $this->_get_theme_status( $theme );
     393
     394        ?>
     395        <div class="install-theme-info"><?php
     396            switch ( $status ) {
     397                case 'update_available':
     398                    echo '<a class="theme-install button button-primary" href="' . esc_url( wp_nonce_url( $update_url, 'upgrade-theme_' . $theme->slug ) ) . '" title="' . esc_attr( sprintf( __( 'Update to version %s' ), $theme->version ) ) . '">' . __( 'Update' ) . '</a>';
     399                    break;
     400                case 'newer_installed':
     401                case 'latest_installed':
     402                    echo '<span class="theme-install" title="' . esc_attr__( 'This theme is already installed and is up to date' ) . '">' . _x( 'Installed', 'theme' ) . '</span>';
     403                    break;
     404                case 'install':
     405                default:
     406                    echo '<a class="theme-install button button-primary" href="' . esc_url( wp_nonce_url( $install_url, 'install-theme_' . $theme->slug ) ) . '">' . __( 'Install' ) . '</a>';
     407                    break;
     408            } ?>
     409            <h3 class="theme-name"><?php echo $name; ?></h3>
     410            <span class="theme-by"><?php printf( __( 'By %s' ), $author ); ?></span>
     411            <?php if ( isset( $theme->screenshot_url ) ): ?>
     412                <img class="theme-screenshot" src="<?php echo esc_url( $theme->screenshot_url ); ?>" alt="" />
     413            <?php endif; ?>
     414            <div class="theme-details">
     415                <?php wp_star_rating( array( 'rating' => $theme->rating, 'type' => 'percent', 'number' => $theme->num_ratings ) ); ?>
     416                <div class="theme-version">
     417                    <strong><?php _e('Version:') ?> </strong>
     418                    <?php echo wp_kses( $theme->version, $themes_allowedtags ); ?>
     419                </div>
     420                <div class="theme-description">
     421                    <?php echo wp_kses( $theme->description, $themes_allowedtags ); ?>
     422                </div>
     423            </div>
     424            <input class="theme-preview-url" type="hidden" value="<?php echo esc_url( $theme->preview_url ); ?>" />
     425        </div>
     426        <?php
     427    }
     428
     429    /**
     430    * Send required variables to JavaScript land
     431    *
     432    * @since 3.4.0
     433    * @access public
     434    *
     435    * @global string $tab  Current tab within Themes->Install screen
     436    * @global string $type Type of search.
     437    *
     438    * @param array $extra_args Unused.
     439    */
     440    public function _js_vars( $extra_args = array() ) {
     441        global $tab, $type;
     442        parent::_js_vars( compact( 'tab', 'type' ) );
     443    }
     444
     445    /**
     446    * Check to see if the theme is already installed.
     447    *
     448    * @since 3.4.0
     449    * @access private
     450    *
     451    * @param object $theme - A WordPress.org Theme API object.
     452    * @return string Theme status.
     453    */
     454    private function _get_theme_status( $theme ) {
     455        $status = 'install';
     456
     457        $installed_theme = wp_get_theme( $theme->slug );
     458        if ( $installed_theme->exists() ) {
     459            if ( version_compare( $installed_theme->get('Version'), $theme->version, '=' ) )
     460                $status = 'latest_installed';
     461            elseif ( version_compare( $installed_theme->get('Version'), $theme->version, '>' ) )
     462                $status = 'newer_installed';
     463            else
     464                $status = 'update_available';
     465        }
     466
     467        return $status;
     468    }
    475469}
  • src/wp-admin/includes/misc.php

    diff --git a/src/wp-admin/includes/misc.php b/src/wp-admin/includes/misc.php
    index 679b9ac5d6..3a782a67ef 100644
    a b  
    1414 * @return bool
    1515 */
    1616function got_mod_rewrite() {
    17         $got_rewrite = apache_mod_loaded('mod_rewrite', true);
    18 
    19         /**
    20         * Filters whether Apache and mod_rewrite are present.
    21         *
    22         * This filter was previously used to force URL rewriting for other servers,
    23         * like nginx. Use the {@see 'got_url_rewrite'} filter in got_url_rewrite() instead.
    24         *
    25         * @since 2.5.0
    26         *
    27         * @see got_url_rewrite()
    28         *
    29         * @param bool $got_rewrite Whether Apache and mod_rewrite are present.
    30         */
    31         return apply_filters( 'got_rewrite', $got_rewrite );
     17    $got_rewrite = apache_mod_loaded('mod_rewrite', true);
     18
     19    /**
     20    * Filters whether Apache and mod_rewrite are present.
     21    *
     22    * This filter was previously used to force URL rewriting for other servers,
     23    * like nginx. Use the {@see 'got_url_rewrite'} filter in got_url_rewrite() instead.
     24    *
     25    * @since 2.5.0
     26    *
     27    * @see got_url_rewrite()
     28    *
     29    * @param bool $got_rewrite Whether Apache and mod_rewrite are present.
     30    */
     31    return apply_filters( 'got_rewrite', $got_rewrite );
    3232}
    3333
    3434/**
    function got_mod_rewrite() { 
    4343 * @return bool Whether the server supports URL rewriting.
    4444 */
    4545function got_url_rewrite() {
    46         $got_url_rewrite = ( got_mod_rewrite() || $GLOBALS['is_nginx'] || iis7_supports_permalinks() );
    47 
    48         /**
    49         * Filters whether URL rewriting is available.
    50         *
    51         * @since 3.7.0
    52         *
    53         * @param bool $got_url_rewrite Whether URL rewriting is available.
    54         */
    55         return apply_filters( 'got_url_rewrite', $got_url_rewrite );
     46    $got_url_rewrite = ( got_mod_rewrite() || $GLOBALS['is_nginx'] || iis7_supports_permalinks() );
     47
     48    /**
     49    * Filters whether URL rewriting is available.
     50    *
     51    * @since 3.7.0
     52    *
     53    * @param bool $got_url_rewrite Whether URL rewriting is available.
     54    */
     55    return apply_filters( 'got_url_rewrite', $got_url_rewrite );
    5656}
    5757
    5858/**
    function got_url_rewrite() { 
    6565 * @return array An array of strings from a file (.htaccess ) from between BEGIN and END markers.
    6666 */
    6767function extract_from_markers( $filename, $marker ) {
    68         $result = array ();
    69 
    70         if (!file_exists( $filename ) ) {
    71                 return $result;
    72         }
    73 
    74         if ( $markerdata = explode( "\n", implode( '', file( $filename ) ) ));
    75         {
    76                 $state = false;
    77                 foreach ( $markerdata as $markerline ) {
    78                         if (strpos($markerline, '# END ' . $marker) !== false)
    79                                 $state = false;
    80                         if ( $state )
    81                                 $result[] = $markerline;
    82                         if (strpos($markerline, '# BEGIN ' . $marker) !== false)
    83                                 $state = true;
    84                 }
    85         }
    86 
    87         return $result;
     68    $result = array ();
     69
     70    if (!file_exists( $filename ) ) {
     71        return $result;
     72    }
     73
     74    if ( $markerdata = explode( "\n", implode( '', file( $filename ) ) ));
     75    {
     76        $state = false;
     77        foreach ( $markerdata as $markerline ) {
     78            if (strpos($markerline, '# END ' . $marker) !== false)
     79                $state = false;
     80            if ( $state )
     81                $result[] = $markerline;
     82            if (strpos($markerline, '# BEGIN ' . $marker) !== false)
     83                $state = true;
     84        }
     85    }
     86
     87    return $result;
    8888}
    8989
    9090/**
    function extract_from_markers( $filename, $marker ) { 
    102102 * @return bool True on write success, false on failure.
    103103 */
    104104function insert_with_markers( $filename, $marker, $insertion ) {
    105         if ( ! file_exists( $filename ) ) {
    106                 if ( ! is_writable( dirname( $filename ) ) ) {
    107                         return false;
    108                 }
    109                 if ( ! touch( $filename ) ) {
    110                         return false;
    111                 }
    112         } elseif ( ! is_writeable( $filename ) ) {
    113                 return false;
    114         }
    115 
    116         if ( ! is_array( $insertion ) ) {
    117                 $insertion = explode( "\n", $insertion );
    118         }
    119 
    120         $start_marker = "# BEGIN {$marker}";
    121         $end_marker   = "# END {$marker}";
    122 
    123         $fp = fopen( $filename, 'r+' );
    124         if ( ! $fp ) {
    125                 return false;
    126         }
    127 
    128         // Attempt to get a lock. If the filesystem supports locking, this will block until the lock is acquired.
    129         flock( $fp, LOCK_EX );
    130 
    131         $lines = array();
    132         while ( ! feof( $fp ) ) {
    133                 $lines[] = rtrim( fgets( $fp ), "\r\n" );
    134         }
    135 
    136         // Split out the existing file into the preceding lines, and those that appear after the marker
    137         $pre_lines = $post_lines = $existing_lines = array();
    138         $found_marker = $found_end_marker = false;
    139         foreach ( $lines as $line ) {
    140                 if ( ! $found_marker && false !== strpos( $line, $start_marker ) ) {
    141                         $found_marker = true;
    142                         continue;
    143                 } elseif ( ! $found_end_marker && false !== strpos( $line, $end_marker ) ) {
    144                         $found_end_marker = true;
    145                         continue;
    146                 }
    147                 if ( ! $found_marker ) {
    148                         $pre_lines[] = $line;
    149                 } elseif ( $found_marker && $found_end_marker ) {
    150                         $post_lines[] = $line;
    151                 } else {
    152                         $existing_lines[] = $line;
    153                 }
    154         }
    155 
    156         // Check to see if there was a change
    157         if ( $existing_lines === $insertion ) {
    158                 flock( $fp, LOCK_UN );
    159                 fclose( $fp );
    160 
    161                 return true;
    162         }
    163 
    164         // Generate the new file data
    165         $new_file_data = implode( "\n", array_merge(
    166                 $pre_lines,
    167                 array( $start_marker ),
    168                 $insertion,
    169                 array( $end_marker ),
    170                 $post_lines
    171         ) );
    172 
    173         // Write to the start of the file, and truncate it to that length
    174         fseek( $fp, 0 );
    175         $bytes = fwrite( $fp, $new_file_data );
    176         if ( $bytes ) {
    177                 ftruncate( $fp, ftell( $fp ) );
    178         }
    179         fflush( $fp );
    180         flock( $fp, LOCK_UN );
    181         fclose( $fp );
    182 
    183         return (bool) $bytes;
     105    if ( ! file_exists( $filename ) ) {
     106        if ( ! is_writable( dirname( $filename ) ) ) {
     107            return false;
     108        }
     109        if ( ! touch( $filename ) ) {
     110            return false;
     111        }
     112    } elseif ( ! is_writeable( $filename ) ) {
     113        return false;
     114    }
     115
     116    if ( ! is_array( $insertion ) ) {
     117        $insertion = explode( "\n", $insertion );
     118    }
     119
     120    $start_marker = "# BEGIN {$marker}";
     121    $end_marker   = "# END {$marker}";
     122
     123    $fp = fopen( $filename, 'r+' );
     124    if ( ! $fp ) {
     125        return false;
     126    }
     127
     128    // Attempt to get a lock. If the filesystem supports locking, this will block until the lock is acquired.
     129    flock( $fp, LOCK_EX );
     130
     131    $lines = array();
     132    while ( ! feof( $fp ) ) {
     133        $lines[] = rtrim( fgets( $fp ), "\r\n" );
     134    }
     135
     136    // Split out the existing file into the preceding lines, and those that appear after the marker
     137    $pre_lines = $post_lines = $existing_lines = array();
     138    $found_marker = $found_end_marker = false;
     139    foreach ( $lines as $line ) {
     140        if ( ! $found_marker && false !== strpos( $line, $start_marker ) ) {
     141            $found_marker = true;
     142            continue;
     143        } elseif ( ! $found_end_marker && false !== strpos( $line, $end_marker ) ) {
     144            $found_end_marker = true;
     145            continue;
     146        }
     147        if ( ! $found_marker ) {
     148            $pre_lines[] = $line;
     149        } elseif ( $found_marker && $found_end_marker ) {
     150            $post_lines[] = $line;
     151        } else {
     152            $existing_lines[] = $line;
     153        }
     154    }
     155
     156    // Check to see if there was a change
     157    if ( $existing_lines === $insertion ) {
     158        flock( $fp, LOCK_UN );
     159        fclose( $fp );
     160
     161        return true;
     162    }
     163
     164    // Generate the new file data
     165    $new_file_data = implode( "\n", array_merge(
     166        $pre_lines,
     167        array( $start_marker ),
     168        $insertion,
     169        array( $end_marker ),
     170        $post_lines
     171    ) );
     172
     173    // Write to the start of the file, and truncate it to that length
     174    fseek( $fp, 0 );
     175    $bytes = fwrite( $fp, $new_file_data );
     176    if ( $bytes ) {
     177        ftruncate( $fp, ftell( $fp ) );
     178    }
     179    fflush( $fp );
     180    flock( $fp, LOCK_UN );
     181    fclose( $fp );
     182
     183    return (bool) $bytes;
    184184}
    185185
    186186/**
    function insert_with_markers( $filename, $marker, $insertion ) { 
    194194 * @global WP_Rewrite $wp_rewrite
    195195 */
    196196function save_mod_rewrite_rules() {
    197         if ( is_multisite() )
    198                 return;
    199 
    200         global $wp_rewrite;
    201 
    202         $home_path = get_home_path();
    203         $htaccess_file = $home_path.'.htaccess';
    204 
    205         /*
    206         * If the file doesn't already exist check for write access to the directory
    207         * and whether we have some rules. Else check for write access to the file.
    208         */
    209         if ((!file_exists($htaccess_file) && is_writable($home_path) && $wp_rewrite->using_mod_rewrite_permalinks()) || is_writable($htaccess_file)) {
    210                 if ( got_mod_rewrite() ) {
    211                         $rules = explode( "\n", $wp_rewrite->mod_rewrite_rules() );
    212                         return insert_with_markers( $htaccess_file, 'WordPress', $rules );
    213                 }
    214         }
    215 
    216         return false;
     197    if ( is_multisite() )
     198        return;
     199
     200    global $wp_rewrite;
     201
     202    $home_path = get_home_path();
     203    $htaccess_file = $home_path.'.htaccess';
     204
     205    /*
     206    * If the file doesn't already exist check for write access to the directory
     207    * and whether we have some rules. Else check for write access to the file.
     208    */
     209    if ((!file_exists($htaccess_file) && is_writable($home_path) && $wp_rewrite->using_mod_rewrite_permalinks()) || is_writable($htaccess_file)) {
     210        if ( got_mod_rewrite() ) {
     211            $rules = explode( "\n", $wp_rewrite->mod_rewrite_rules() );
     212            return insert_with_markers( $htaccess_file, 'WordPress', $rules );
     213        }
     214    }
     215
     216    return false;
    217217}
    218218
    219219/**
    function save_mod_rewrite_rules() { 
    227227 * @return bool True if web.config was updated successfully
    228228 */
    229229function iis7_save_url_rewrite_rules(){
    230         if ( is_multisite() )
    231                 return;
    232 
    233         global $wp_rewrite;
    234 
    235         $home_path = get_home_path();
    236         $web_config_file = $home_path . 'web.config';
    237 
    238         // Using win_is_writable() instead of is_writable() because of a bug in Windows PHP
    239         if ( iis7_supports_permalinks() && ( ( ! file_exists($web_config_file) && win_is_writable($home_path) && $wp_rewrite->using_mod_rewrite_permalinks() ) || win_is_writable($web_config_file) ) ) {
    240                 $rule = $wp_rewrite->iis7_url_rewrite_rules(false, '', '');
    241                 if ( ! empty($rule) ) {
    242                         return iis7_add_rewrite_rule($web_config_file, $rule);
    243                 } else {
    244                         return iis7_delete_rewrite_rule($web_config_file);
    245                 }
    246         }
    247         return false;
     230    if ( is_multisite() )
     231        return;
     232
     233    global $wp_rewrite;
     234
     235    $home_path = get_home_path();
     236    $web_config_file = $home_path . 'web.config';
     237
     238    // Using win_is_writable() instead of is_writable() because of a bug in Windows PHP
     239    if ( iis7_supports_permalinks() && ( ( ! file_exists($web_config_file) && win_is_writable($home_path) && $wp_rewrite->using_mod_rewrite_permalinks() ) || win_is_writable($web_config_file) ) ) {
     240        $rule = $wp_rewrite->iis7_url_rewrite_rules(false, '', '');
     241        if ( ! empty($rule) ) {
     242            return iis7_add_rewrite_rule($web_config_file, $rule);
     243        } else {
     244            return iis7_delete_rewrite_rule($web_config_file);
     245        }
     246    }
     247    return false;
    248248}
    249249
    250250/**
    function iis7_save_url_rewrite_rules(){ 
    255255 * @param string $file
    256256 */
    257257function update_recently_edited( $file ) {
    258         $oldfiles = (array ) get_option( 'recently_edited' );
    259         if ( $oldfiles ) {
    260                 $oldfiles = array_reverse( $oldfiles );
    261                 $oldfiles[] = $file;
    262                 $oldfiles = array_reverse( $oldfiles );
    263                 $oldfiles = array_unique( $oldfiles );
    264                 if ( 5 < count( $oldfiles ))
    265                         array_pop( $oldfiles );
    266         } else {
    267                 $oldfiles[] = $file;
    268         }
    269         update_option( 'recently_edited', $oldfiles );
     258    $oldfiles = (array ) get_option( 'recently_edited' );
     259    if ( $oldfiles ) {
     260        $oldfiles = array_reverse( $oldfiles );
     261        $oldfiles[] = $file;
     262        $oldfiles = array_reverse( $oldfiles );
     263        $oldfiles = array_unique( $oldfiles );
     264        if ( 5 < count( $oldfiles ))
     265            array_pop( $oldfiles );
     266    } else {
     267        $oldfiles[] = $file;
     268    }
     269    update_option( 'recently_edited', $oldfiles );
    270270}
    271271
    272272/**
    function update_recently_edited( $file ) { 
    278278 * @param string $value
    279279 */
    280280function update_home_siteurl( $old_value, $value ) {
    281         if ( wp_installing() )
    282                 return;
    283 
    284         if ( is_multisite() && ms_is_switched() ) {
    285                 delete_option( 'rewrite_rules' );
    286         } else {
    287                 flush_rewrite_rules();
    288         }
     281    if ( wp_installing() )
     282        return;
     283
     284    if ( is_multisite() && ms_is_switched() ) {
     285        delete_option( 'rewrite_rules' );
     286    } else {
     287        flush_rewrite_rules();
     288    }
    289289}
    290290
    291291
    function update_home_siteurl( $old_value, $value ) { 
    301301 * @param array $vars An array of globals to reset.
    302302 */
    303303function wp_reset_vars( $vars ) {
    304         foreach ( $vars as $var ) {
    305                 if ( empty( $_POST[ $var ] ) ) {
    306                         if ( empty( $_GET[ $var ] ) ) {
    307                                 $GLOBALS[ $var ] = '';
    308                         } else {
    309                                 $GLOBALS[ $var ] = $_GET[ $var ];
    310                         }
    311                 } else {
    312                         $GLOBALS[ $var ] = $_POST[ $var ];
    313                 }
    314         }
     304    foreach ( $vars as $var ) {
     305        if ( empty( $_POST[ $var ] ) ) {
     306            if ( empty( $_GET[ $var ] ) ) {
     307                $GLOBALS[ $var ] = '';
     308            } else {
     309                $GLOBALS[ $var ] = $_GET[ $var ];
     310            }
     311        } else {
     312            $GLOBALS[ $var ] = $_POST[ $var ];
     313        }
     314    }
     315}
     316
     317/**
     318 * Return $_POST[ $var ] or $_GET[ $var ] value.
     319 *
     320 * This functions returns $_POST[ $var ] or $_GET[ $var ] value in this order
     321 *  if they are not empty, otherwise it returns an empty string.
     322 *
     323 * @since 4.8.0
     324 *
     325 * @param  string $var The key of the array for getting value to return.
     326 *
     327 * @return mixed $_POST[ $var ] or $_GET[ $var ] value or an empty string.
     328 */
     329function wp_assign_request_var( $var ) {
     330    if ( empty( $_POST[ $var ] ) ) {
     331        if ( empty( $_GET[ $var ] ) ) {
     332            return '';
     333        } else {
     334            return $_GET[ $var ];
     335        }
     336    } else {
     337        return $_POST[ $var ];
     338    }
    315339}
    316340
    317341/**
    function wp_reset_vars( $vars ) { 
    322346 * @param string|WP_Error $message
    323347 */
    324348function show_message($message) {
    325         if ( is_wp_error($message) ){
    326                 if ( $message->get_error_data() && is_string( $message->get_error_data() ) )
    327                         $message = $message->get_error_message() . ': ' . $message->get_error_data();
    328                 else
    329                         $message = $message->get_error_message();
    330         }
    331         echo "<p>$message</p>\n";
    332         wp_ob_end_flush_all();
    333         flush();
     349    if ( is_wp_error($message) ){
     350        if ( $message->get_error_data() && is_string( $message->get_error_data() ) )
     351            $message = $message->get_error_message() . ': ' . $message->get_error_data();
     352        else
     353            $message = $message->get_error_message();
     354    }
     355    echo "<p>$message</p>\n";
     356    wp_ob_end_flush_all();
     357    flush();
    334358}
    335359
    336360/**
    function show_message($message) { 
    340364 * @return array
    341365 */
    342366function wp_doc_link_parse( $content ) {
    343         if ( !is_string( $content ) || empty( $content ) )
    344                 return array();
    345 
    346         if ( !function_exists('token_get_all') )
    347                 return array();
    348 
    349         $tokens = token_get_all( $content );
    350         $count = count( $tokens );
    351         $functions = array();
    352         $ignore_functions = array();
    353         for ( $t = 0; $t < $count - 2; $t++ ) {
    354                 if ( ! is_array( $tokens[ $t ] ) ) {
    355                         continue;
    356                 }
    357 
    358                 if ( T_STRING == $tokens[ $t ][0] && ( '(' == $tokens[ $t + 1 ] || '(' == $tokens[ $t + 2 ] ) ) {
    359                         // If it's a function or class defined locally, there's not going to be any docs available
    360                         if ( ( isset( $tokens[ $t - 2 ][1] ) && in_array( $tokens[ $t - 2 ][1], array( 'function', 'class' ) ) ) || ( isset( $tokens[ $t - 2 ][0] ) && T_OBJECT_OPERATOR == $tokens[ $t - 1 ][0] ) ) {
    361                                 $ignore_functions[] = $tokens[$t][1];
    362                         }
    363                         // Add this to our stack of unique references
    364                         $functions[] = $tokens[$t][1];
    365                 }
    366         }
    367 
    368         $functions = array_unique( $functions );
    369         sort( $functions );
    370 
    371         /**
    372         * Filters the list of functions and classes to be ignored from the documentation lookup.
    373         *
    374         * @since 2.8.0
    375         *
    376         * @param array $ignore_functions Functions and classes to be ignored.
    377         */
    378         $ignore_functions = apply_filters( 'documentation_ignore_functions', $ignore_functions );
    379 
    380         $ignore_functions = array_unique( $ignore_functions );
    381 
    382         $out = array();
    383         foreach ( $functions as $function ) {
    384                 if ( in_array( $function, $ignore_functions ) )
    385                         continue;
    386                 $out[] = $function;
    387         }
    388 
    389         return $out;
     367    if ( !is_string( $content ) || empty( $content ) )
     368        return array();
     369
     370    if ( !function_exists('token_get_all') )
     371        return array();
     372
     373    $tokens = token_get_all( $content );
     374    $count = count( $tokens );
     375    $functions = array();
     376    $ignore_functions = array();
     377    for ( $t = 0; $t < $count - 2; $t++ ) {
     378        if ( ! is_array( $tokens[ $t ] ) ) {
     379            continue;
     380        }
     381
     382        if ( T_STRING == $tokens[ $t ][0] && ( '(' == $tokens[ $t + 1 ] || '(' == $tokens[ $t + 2 ] ) ) {
     383            // If it's a function or class defined locally, there's not going to be any docs available
     384            if ( ( isset( $tokens[ $t - 2 ][1] ) && in_array( $tokens[ $t - 2 ][1], array( 'function', 'class' ) ) ) || ( isset( $tokens[ $t - 2 ][0] ) && T_OBJECT_OPERATOR == $tokens[ $t - 1 ][0] ) ) {
     385                $ignore_functions[] = $tokens[$t][1];
     386            }
     387            // Add this to our stack of unique references
     388            $functions[] = $tokens[$t][1];
     389        }
     390    }
     391
     392    $functions = array_unique( $functions );
     393    sort( $functions );
     394
     395    /**
     396    * Filters the list of functions and classes to be ignored from the documentation lookup.
     397    *
     398    * @since 2.8.0
     399    *
     400    * @param array $ignore_functions Functions and classes to be ignored.
     401    */
     402    $ignore_functions = apply_filters( 'documentation_ignore_functions', $ignore_functions );
     403
     404    $ignore_functions = array_unique( $ignore_functions );
     405
     406    $out = array();
     407    foreach ( $functions as $function ) {
     408        if ( in_array( $function, $ignore_functions ) )
     409            continue;
     410        $out[] = $function;
     411    }
     412
     413    return $out;
    390414}
    391415
    392416/**
    function wp_doc_link_parse( $content ) { 
    396420 */
    397421function set_screen_options() {
    398422
    399         if ( isset($_POST['wp_screen_options']) && is_array($_POST['wp_screen_options']) ) {
    400                 check_admin_referer( 'screen-options-nonce', 'screenoptionnonce' );
    401 
    402                 if ( !$user = wp_get_current_user() )
    403                         return;
    404                 $option = $_POST['wp_screen_options']['option'];
    405                 $value = $_POST['wp_screen_options']['value'];
    406 
    407                 if ( $option != sanitize_key( $option ) )
    408                         return;
    409 
    410                 $map_option = $option;
    411                 $type = str_replace('edit_', '', $map_option);
    412                 $type = str_replace('_per_page', '', $type);
    413                 if ( in_array( $type, get_taxonomies() ) )
    414                         $map_option = 'edit_tags_per_page';
    415                 elseif ( in_array( $type, get_post_types() ) )
    416                         $map_option = 'edit_per_page';
    417                 else
    418                         $option = str_replace('-', '_', $option);
    419 
    420                 switch ( $map_option ) {
    421                         case 'edit_per_page':
    422                         case 'users_per_page':
    423                         case 'edit_comments_per_page':
    424                         case 'upload_per_page':
    425                         case 'edit_tags_per_page':
    426                         case 'plugins_per_page':
    427                         // Network admin
    428                         case 'sites_network_per_page':
    429                         case 'users_network_per_page':
    430                         case 'site_users_network_per_page':
    431                         case 'plugins_network_per_page':
    432                         case 'themes_network_per_page':
    433                         case 'site_themes_network_per_page':
    434                                 $value = (int) $value;
    435                                 if ( $value < 1 || $value > 999 )
    436                                         return;
    437                                 break;
    438                         default:
    439 
    440                                 /**
    441                                 * Filters a screen option value before it is set.
    442                                 *
    443                                 * The filter can also be used to modify non-standard [items]_per_page
    444                                 * settings. See the parent function for a full list of standard options.
    445                                 *
    446                                 * Returning false to the filter will skip saving the current option.
    447                                 *
    448                                 * @since 2.8.0
    449                                 *
    450                                 * @see set_screen_options()
    451                                 *
    452                                 * @param bool|int $value  Screen option value. Default false to skip.
    453                                 * @param string   $option The option name.
    454                                 * @param int      $value  The number of rows to use.
    455                                 */
    456                                 $value = apply_filters( 'set-screen-option', false, $option, $value );
    457 
    458                                 if ( false === $value )
    459                                         return;
    460                                 break;
    461                 }
    462 
    463                 update_user_meta($user->ID, $option, $value);
    464 
    465                 $url = remove_query_arg( array( 'pagenum', 'apage', 'paged' ), wp_get_referer() );
    466                 if ( isset( $_POST['mode'] ) ) {
    467                         $url = add_query_arg( array( 'mode' => $_POST['mode'] ), $url );
    468                 }
    469 
    470                 wp_safe_redirect( $url );
    471                 exit;
    472         }
     423    if ( isset($_POST['wp_screen_options']) && is_array($_POST['wp_screen_options']) ) {
     424        check_admin_referer( 'screen-options-nonce', 'screenoptionnonce' );
     425
     426        if ( !$user = wp_get_current_user() )
     427            return;
     428        $option = $_POST['wp_screen_options']['option'];
     429        $value = $_POST['wp_screen_options']['value'];
     430
     431        if ( $option != sanitize_key( $option ) )
     432            return;
     433
     434        $map_option = $option;
     435        $type = str_replace('edit_', '', $map_option);
     436        $type = str_replace('_per_page', '', $type);
     437        if ( in_array( $type, get_taxonomies() ) )
     438            $map_option = 'edit_tags_per_page';
     439        elseif ( in_array( $type, get_post_types() ) )
     440            $map_option = 'edit_per_page';
     441        else
     442            $option = str_replace('-', '_', $option);
     443
     444        switch ( $map_option ) {
     445            case 'edit_per_page':
     446            case 'users_per_page':
     447            case 'edit_comments_per_page':
     448            case 'upload_per_page':
     449            case 'edit_tags_per_page':
     450            case 'plugins_per_page':
     451            // Network admin
     452            case 'sites_network_per_page':
     453            case 'users_network_per_page':
     454            case 'site_users_network_per_page':
     455            case 'plugins_network_per_page':
     456            case 'themes_network_per_page':
     457            case 'site_themes_network_per_page':
     458                $value = (int) $value;
     459                if ( $value < 1 || $value > 999 )
     460                    return;
     461                break;
     462            default:
     463
     464                /**
     465                * Filters a screen option value before it is set.
     466                *
     467                * The filter can also be used to modify non-standard [items]_per_page
     468                * settings. See the parent function for a full list of standard options.
     469                *
     470                * Returning false to the filter will skip saving the current option.
     471                *
     472                * @since 2.8.0
     473                *
     474                * @see set_screen_options()
     475                *
     476                * @param bool|int $value  Screen option value. Default false to skip.
     477                * @param string   $option The option name.
     478                * @param int      $value  The number of rows to use.
     479                */
     480                $value = apply_filters( 'set-screen-option', false, $option, $value );
     481
     482                if ( false === $value )
     483                    return;
     484                break;
     485        }
     486
     487        update_user_meta($user->ID, $option, $value);
     488
     489        $url = remove_query_arg( array( 'pagenum', 'apage', 'paged' ), wp_get_referer() );
     490        if ( isset( $_POST['mode'] ) ) {
     491            $url = add_query_arg( array( 'mode' => $_POST['mode'] ), $url );
     492        }
     493
     494        wp_safe_redirect( $url );
     495        exit;
     496    }
    473497}
    474498
    475499/**
    function set_screen_options() { 
    481505 * @param string $filename The file path to the configuration file
    482506 */
    483507function iis7_rewrite_rule_exists($filename) {
    484         if ( ! file_exists($filename) )
    485                 return false;
    486         if ( ! class_exists( 'DOMDocument', false ) ) {
    487                 return false;
    488         }
    489 
    490         $doc = new DOMDocument();
    491         if ( $doc->load($filename) === false )
    492                 return false;
    493         $xpath = new DOMXPath($doc);
    494         $rules = $xpath->query('/configuration/system.webServer/rewrite/rules/rule[starts-with(@name,\'wordpress\')] | /configuration/system.webServer/rewrite/rules/rule[starts-with(@name,\'WordPress\')]');
    495         if ( $rules->length == 0 )
    496                 return false;
    497         else
    498                 return true;
     508    if ( ! file_exists($filename) )
     509        return false;
     510    if ( ! class_exists( 'DOMDocument', false ) ) {
     511        return false;
     512    }
     513
     514    $doc = new DOMDocument();
     515    if ( $doc->load($filename) === false )
     516        return false;
     517    $xpath = new DOMXPath($doc);
     518    $rules = $xpath->query('/configuration/system.webServer/rewrite/rules/rule[starts-with(@name,\'wordpress\')] | /configuration/system.webServer/rewrite/rules/rule[starts-with(@name,\'WordPress\')]');
     519    if ( $rules->length == 0 )
     520        return false;
     521    else
     522        return true;
    499523}
    500524
    501525/**
    function iis7_rewrite_rule_exists($filename) { 
    507531 * @return bool
    508532 */
    509533function iis7_delete_rewrite_rule($filename) {
    510         // If configuration file does not exist then rules also do not exist so there is nothing to delete
    511         if ( ! file_exists($filename) )
    512                 return true;
    513 
    514         if ( ! class_exists( 'DOMDocument', false ) ) {
    515                 return false;
    516         }
    517 
    518         $doc = new DOMDocument();
    519         $doc->preserveWhiteSpace = false;
    520 
    521         if ( $doc -> load($filename) === false )
    522                 return false;
    523         $xpath = new DOMXPath($doc);
    524         $rules = $xpath->query('/configuration/system.webServer/rewrite/rules/rule[starts-with(@name,\'wordpress\')] | /configuration/system.webServer/rewrite/rules/rule[starts-with(@name,\'WordPress\')]');
    525         if ( $rules->length > 0 ) {
    526                 $child = $rules->item(0);
    527                 $parent = $child->parentNode;
    528                 $parent->removeChild($child);
    529                 $doc->formatOutput = true;
    530                 saveDomDocument($doc, $filename);
    531         }
    532         return true;
     534    // If configuration file does not exist then rules also do not exist so there is nothing to delete
     535    if ( ! file_exists($filename) )
     536        return true;
     537
     538    if ( ! class_exists( 'DOMDocument', false ) ) {
     539        return false;
     540    }
     541
     542    $doc = new DOMDocument();
     543    $doc->preserveWhiteSpace = false;
     544
     545    if ( $doc -> load($filename) === false )
     546        return false;
     547    $xpath = new DOMXPath($doc);
     548    $rules = $xpath->query('/configuration/system.webServer/rewrite/rules/rule[starts-with(@name,\'wordpress\')] | /configuration/system.webServer/rewrite/rules/rule[starts-with(@name,\'WordPress\')]');
     549    if ( $rules->length > 0 ) {
     550        $child = $rules->item(0);
     551        $parent = $child->parentNode;
     552        $parent->removeChild($child);
     553        $doc->formatOutput = true;
     554        saveDomDocument($doc, $filename);
     555    }
     556    return true;
    533557}
    534558
    535559/**
    function iis7_delete_rewrite_rule($filename) { 
    542566 * @return bool
    543567 */
    544568function iis7_add_rewrite_rule($filename, $rewrite_rule) {
    545         if ( ! class_exists( 'DOMDocument', false ) ) {
    546                 return false;
    547         }
    548 
    549         // If configuration file does not exist then we create one.
    550         if ( ! file_exists($filename) ) {
    551                 $fp = fopen( $filename, 'w');
    552                 fwrite($fp, '<configuration/>');
    553                 fclose($fp);
    554         }
    555 
    556         $doc = new DOMDocument();
    557         $doc->preserveWhiteSpace = false;
    558 
    559         if ( $doc->load($filename) === false )
    560                 return false;
    561 
    562         $xpath = new DOMXPath($doc);
    563 
    564         // First check if the rule already exists as in that case there is no need to re-add it
    565         $wordpress_rules = $xpath->query('/configuration/system.webServer/rewrite/rules/rule[starts-with(@name,\'wordpress\')] | /configuration/system.webServer/rewrite/rules/rule[starts-with(@name,\'WordPress\')]');
    566         if ( $wordpress_rules->length > 0 )
    567                 return true;
    568 
    569         // Check the XPath to the rewrite rule and create XML nodes if they do not exist
    570         $xmlnodes = $xpath->query('/configuration/system.webServer/rewrite/rules');
    571         if ( $xmlnodes->length > 0 ) {
    572                 $rules_node = $xmlnodes->item(0);
    573         } else {
    574                 $rules_node = $doc->createElement('rules');
    575 
    576                 $xmlnodes = $xpath->query('/configuration/system.webServer/rewrite');
    577                 if ( $xmlnodes->length > 0 ) {
    578                         $rewrite_node = $xmlnodes->item(0);
    579                         $rewrite_node->appendChild($rules_node);
    580                 } else {
    581                         $rewrite_node = $doc->createElement('rewrite');
    582                         $rewrite_node->appendChild($rules_node);
    583 
    584                         $xmlnodes = $xpath->query('/configuration/system.webServer');
    585                         if ( $xmlnodes->length > 0 ) {
    586                                 $system_webServer_node = $xmlnodes->item(0);
    587                                 $system_webServer_node->appendChild($rewrite_node);
    588                         } else {
    589                                 $system_webServer_node = $doc->createElement('system.webServer');
    590                                 $system_webServer_node->appendChild($rewrite_node);
    591 
    592                                 $xmlnodes = $xpath->query('/configuration');
    593                                 if ( $xmlnodes->length > 0 ) {
    594                                         $config_node = $xmlnodes->item(0);
    595                                         $config_node->appendChild($system_webServer_node);
    596                                 } else {
    597                                         $config_node = $doc->createElement('configuration');
    598                                         $doc->appendChild($config_node);
    599                                         $config_node->appendChild($system_webServer_node);
    600                                 }
    601                         }
    602                 }
    603         }
    604 
    605         $rule_fragment = $doc->createDocumentFragment();
    606         $rule_fragment->appendXML($rewrite_rule);
    607         $rules_node->appendChild($rule_fragment);
    608 
    609         $doc->encoding = "UTF-8";
    610         $doc->formatOutput = true;
    611         saveDomDocument($doc, $filename);
    612 
    613         return true;
     569    if ( ! class_exists( 'DOMDocument', false ) ) {
     570        return false;
     571    }
     572
     573    // If configuration file does not exist then we create one.
     574    if ( ! file_exists($filename) ) {
     575        $fp = fopen( $filename, 'w');
     576        fwrite($fp, '<configuration/>');
     577        fclose($fp);
     578    }
     579
     580    $doc = new DOMDocument();
     581    $doc->preserveWhiteSpace = false;
     582
     583    if ( $doc->load($filename) === false )
     584        return false;
     585
     586    $xpath = new DOMXPath($doc);
     587
     588    // First check if the rule already exists as in that case there is no need to re-add it
     589    $wordpress_rules = $xpath->query('/configuration/system.webServer/rewrite/rules/rule[starts-with(@name,\'wordpress\')] | /configuration/system.webServer/rewrite/rules/rule[starts-with(@name,\'WordPress\')]');
     590    if ( $wordpress_rules->length > 0 )
     591        return true;
     592
     593    // Check the XPath to the rewrite rule and create XML nodes if they do not exist
     594    $xmlnodes = $xpath->query('/configuration/system.webServer/rewrite/rules');
     595    if ( $xmlnodes->length > 0 ) {
     596        $rules_node = $xmlnodes->item(0);
     597    } else {
     598        $rules_node = $doc->createElement('rules');
     599
     600        $xmlnodes = $xpath->query('/configuration/system.webServer/rewrite');
     601        if ( $xmlnodes->length > 0 ) {
     602            $rewrite_node = $xmlnodes->item(0);
     603            $rewrite_node->appendChild($rules_node);
     604        } else {
     605            $rewrite_node = $doc->createElement('rewrite');
     606            $rewrite_node->appendChild($rules_node);
     607
     608            $xmlnodes = $xpath->query('/configuration/system.webServer');
     609            if ( $xmlnodes->length > 0 ) {
     610                $system_webServer_node = $xmlnodes->item(0);
     611                $system_webServer_node->appendChild($rewrite_node);
     612            } else {
     613                $system_webServer_node = $doc->createElement('system.webServer');
     614                $system_webServer_node->appendChild($rewrite_node);
     615
     616                $xmlnodes = $xpath->query('/configuration');
     617                if ( $xmlnodes->length > 0 ) {
     618                    $config_node = $xmlnodes->item(0);
     619                    $config_node->appendChild($system_webServer_node);
     620                } else {
     621                    $config_node = $doc->createElement('configuration');
     622                    $doc->appendChild($config_node);
     623                    $config_node->appendChild($system_webServer_node);
     624                }
     625            }
     626        }
     627    }
     628
     629    $rule_fragment = $doc->createDocumentFragment();
     630    $rule_fragment->appendXML($rewrite_rule);
     631    $rules_node->appendChild($rule_fragment);
     632
     633    $doc->encoding = "UTF-8";
     634    $doc->formatOutput = true;
     635    saveDomDocument($doc, $filename);
     636
     637    return true;
    614638}
    615639
    616640/**
    function iis7_add_rewrite_rule($filename, $rewrite_rule) { 
    622646 * @param string $filename
    623647 */
    624648function saveDomDocument($doc, $filename) {
    625         $config = $doc->saveXML();
    626         $config = preg_replace("/([^\r])\n/", "$1\r\n", $config);
    627         $fp = fopen($filename, 'w');
    628         fwrite($fp, $config);
    629         fclose($fp);
     649    $config = $doc->saveXML();
     650    $config = preg_replace("/([^\r])\n/", "$1\r\n", $config);
     651    $fp = fopen($filename, 'w');
     652    fwrite($fp, $config);
     653    fclose($fp);
    630654}
    631655
    632656/**
    function saveDomDocument($doc, $filename) { 
    639663 * @param int $user_id User ID.
    640664 */
    641665function admin_color_scheme_picker( $user_id ) {
    642         global $_wp_admin_css_colors;
    643 
    644         ksort( $_wp_admin_css_colors );
    645 
    646         if ( isset( $_wp_admin_css_colors['fresh'] ) ) {
    647                 // Set Default ('fresh') and Light should go first.
    648                 $_wp_admin_css_colors = array_filter( array_merge( array( 'fresh' => '', 'light' => '' ), $_wp_admin_css_colors ) );
    649         }
    650 
    651         $current_color = get_user_option( 'admin_color', $user_id );
    652 
    653         if ( empty( $current_color ) || ! isset( $_wp_admin_css_colors[ $current_color ] ) ) {
    654                 $current_color = 'fresh';
    655         }
    656 
    657         ?>
    658         <fieldset id="color-picker" class="scheme-list">
    659                 <legend class="screen-reader-text"><span><?php _e( 'Admin Color Scheme' ); ?></span></legend>
    660                 <?php
    661                 wp_nonce_field( 'save-color-scheme', 'color-nonce', false );
    662                 foreach ( $_wp_admin_css_colors as $color => $color_info ) :
    663 
    664                         ?>
    665                         <div class="color-option <?php echo ( $color == $current_color ) ? 'selected' : ''; ?>">
    666                                 <input name="admin_color" id="admin_color_<?php echo esc_attr( $color ); ?>" type="radio" value="<?php echo esc_attr( $color ); ?>" class="tog" <?php checked( $color, $current_color ); ?> />
    667                                 <input type="hidden" class="css_url" value="<?php echo esc_url( $color_info->url ); ?>" />
    668                                 <input type="hidden" class="icon_colors" value="<?php echo esc_attr( wp_json_encode( array( 'icons' => $color_info->icon_colors ) ) ); ?>" />
    669                                 <label for="admin_color_<?php echo esc_attr( $color ); ?>"><?php echo esc_html( $color_info->name ); ?></label>
    670                                 <table class="color-palette">
    671                                         <tr>
    672                                         <?php
    673 
    674                                         foreach ( $color_info->colors as $html_color ) {
    675                                                 ?>
    676                                                 <td style="background-color: <?php echo esc_attr( $html_color ); ?>">&nbsp;</td>
    677                                                 <?php
    678                                         }
    679 
    680                                         ?>
    681                                         </tr>
    682                                 </table>
    683                         </div>
    684                         <?php
    685 
    686                 endforeach;
    687 
    688         ?>
    689         </fieldset>
    690         <?php
     666    global $_wp_admin_css_colors;
     667
     668    ksort( $_wp_admin_css_colors );
     669
     670    if ( isset( $_wp_admin_css_colors['fresh'] ) ) {
     671        // Set Default ('fresh') and Light should go first.
     672        $_wp_admin_css_colors = array_filter( array_merge( array( 'fresh' => '', 'light' => '' ), $_wp_admin_css_colors ) );
     673    }
     674
     675    $current_color = get_user_option( 'admin_color', $user_id );
     676
     677    if ( empty( $current_color ) || ! isset( $_wp_admin_css_colors[ $current_color ] ) ) {
     678        $current_color = 'fresh';
     679    }
     680
     681    ?>
     682    <fieldset id="color-picker" class="scheme-list">
     683        <legend class="screen-reader-text"><span><?php _e( 'Admin Color Scheme' ); ?></span></legend>
     684        <?php
     685        wp_nonce_field( 'save-color-scheme', 'color-nonce', false );
     686        foreach ( $_wp_admin_css_colors as $color => $color_info ) :
     687
     688            ?>
     689            <div class="color-option <?php echo ( $color == $current_color ) ? 'selected' : ''; ?>">
     690                <input name="admin_color" id="admin_color_<?php echo esc_attr( $color ); ?>" type="radio" value="<?php echo esc_attr( $color ); ?>" class="tog" <?php checked( $color, $current_color ); ?> />
     691                <input type="hidden" class="css_url" value="<?php echo esc_url( $color_info->url ); ?>" />
     692                <input type="hidden" class="icon_colors" value="<?php echo esc_attr( wp_json_encode( array( 'icons' => $color_info->icon_colors ) ) ); ?>" />
     693                <label for="admin_color_<?php echo esc_attr( $color ); ?>"><?php echo esc_html( $color_info->name ); ?></label>
     694                <table class="color-palette">
     695                    <tr>
     696                    <?php
     697
     698                    foreach ( $color_info->colors as $html_color ) {
     699                        ?>
     700                        <td style="background-color: <?php echo esc_attr( $html_color ); ?>">&nbsp;</td>
     701                        <?php
     702                    }
     703
     704                    ?>
     705                    </tr>
     706                </table>
     707            </div>
     708            <?php
     709
     710        endforeach;
     711
     712    ?>
     713    </fieldset>
     714    <?php
    691715}
    692716
    693717/**
    function admin_color_scheme_picker( $user_id ) { 
    695719 * @global array $_wp_admin_css_colors
    696720 */
    697721function wp_color_scheme_settings() {
    698         global $_wp_admin_css_colors;
     722    global $_wp_admin_css_colors;
    699723
    700         $color_scheme = get_user_option( 'admin_color' );
     724    $color_scheme = get_user_option( 'admin_color' );
    701725
    702         // It's possible to have a color scheme set that is no longer registered.
    703         if ( empty( $_wp_admin_css_colors[ $color_scheme ] ) ) {
    704                 $color_scheme = 'fresh';
    705         }
     726    // It's possible to have a color scheme set that is no longer registered.
     727    if ( empty( $_wp_admin_css_colors[ $color_scheme ] ) ) {
     728        $color_scheme = 'fresh';
     729    }
    706730
    707         if ( ! empty( $_wp_admin_css_colors[ $color_scheme ]->icon_colors ) ) {
    708                 $icon_colors = $_wp_admin_css_colors[ $color_scheme ]->icon_colors;
    709         } elseif ( ! empty( $_wp_admin_css_colors['fresh']->icon_colors ) ) {
    710                 $icon_colors = $_wp_admin_css_colors['fresh']->icon_colors;
    711         } else {
    712                 // Fall back to the default set of icon colors if the default scheme is missing.
    713                 $icon_colors = array( 'base' => '#82878c', 'focus' => '#00a0d2', 'current' => '#fff' );
    714         }
     731    if ( ! empty( $_wp_admin_css_colors[ $color_scheme ]->icon_colors ) ) {
     732        $icon_colors = $_wp_admin_css_colors[ $color_scheme ]->icon_colors;
     733    } elseif ( ! empty( $_wp_admin_css_colors['fresh']->icon_colors ) ) {
     734        $icon_colors = $_wp_admin_css_colors['fresh']->icon_colors;
     735    } else {
     736        // Fall back to the default set of icon colors if the default scheme is missing.
     737        $icon_colors = array( 'base' => '#82878c', 'focus' => '#00a0d2', 'current' => '#fff' );
     738    }
    715739
    716         echo '<script type="text/javascript">var _wpColorScheme = ' . wp_json_encode( array( 'icons' => $icon_colors ) ) . ";</script>\n";
     740    echo '<script type="text/javascript">var _wpColorScheme = ' . wp_json_encode( array( 'icons' => $icon_colors ) ) . ";</script>\n";
    717741}
    718742
    719743/**
    720744 * @since 3.3.0
    721745 */
    722746function _ipad_meta() {
    723         if ( wp_is_mobile() ) {
    724                 ?>
    725                 <meta name="viewport" id="viewport-meta" content="width=device-width, initial-scale=1">
    726                 <?php
    727         }
     747    if ( wp_is_mobile() ) {
     748        ?>
     749        <meta name="viewport" id="viewport-meta" content="width=device-width, initial-scale=1">
     750        <?php
     751    }
    728752}
    729753
    730754/**
    function _ipad_meta() { 
    738762 * @return array The Heartbeat response.
    739763 */
    740764function wp_check_locked_posts( $response, $data, $screen_id ) {
    741         $checked = array();
     765    $checked = array();
    742766
    743         if ( array_key_exists( 'wp-check-locked-posts', $data ) && is_array( $data['wp-check-locked-posts'] ) ) {
    744                 foreach ( $data['wp-check-locked-posts'] as $key ) {
    745                         if ( ! $post_id = absint( substr( $key, 5 ) ) )
    746                                 continue;
     767    if ( array_key_exists( 'wp-check-locked-posts', $data ) && is_array( $data['wp-check-locked-posts'] ) ) {
     768        foreach ( $data['wp-check-locked-posts'] as $key ) {
     769            if ( ! $post_id = absint( substr( $key, 5 ) ) )
     770                continue;
    747771
    748                         if ( ( $user_id = wp_check_post_lock( $post_id ) ) && ( $user = get_userdata( $user_id ) ) && current_user_can( 'edit_post', $post_id ) ) {
    749                                 $send = array( 'text' => sprintf( __( '%s is currently editing' ), $user->display_name ) );
     772            if ( ( $user_id = wp_check_post_lock( $post_id ) ) && ( $user = get_userdata( $user_id ) ) && current_user_can( 'edit_post', $post_id ) ) {
     773                $send = array( 'text' => sprintf( __( '%s is currently editing' ), $user->display_name ) );
    750774
    751                                 if ( ( $avatar = get_avatar( $user->ID, 18 ) ) && preg_match( "|src='([^']+)'|", $avatar, $matches ) )
    752                                         $send['avatar_src'] = $matches[1];
     775                if ( ( $avatar = get_avatar( $user->ID, 18 ) ) && preg_match( "|src='([^']+)'|", $avatar, $matches ) )
     776                    $send['avatar_src'] = $matches[1];
    753777
    754                                 $checked[$key] = $send;
    755                         }
    756                 }
    757         }
     778                $checked[$key] = $send;
     779            }
     780        }
     781    }
    758782
    759         if ( ! empty( $checked ) )
    760                 $response['wp-check-locked-posts'] = $checked;
     783    if ( ! empty( $checked ) )
     784        $response['wp-check-locked-posts'] = $checked;
    761785
    762         return $response;
     786    return $response;
    763787}
    764788
    765789/**
    function wp_check_locked_posts( $response, $data, $screen_id ) { 
    773797 * @return array The Heartbeat response.
    774798 */
    775799function wp_refresh_post_lock( $response, $data, $screen_id ) {
    776         if ( array_key_exists( 'wp-refresh-post-lock', $data ) ) {
    777                 $received = $data['wp-refresh-post-lock'];
    778                 $send = array();
     800    if ( array_key_exists( 'wp-refresh-post-lock', $data ) ) {
     801        $received = $data['wp-refresh-post-lock'];
     802        $send = array();
    779803
    780                 if ( ! $post_id = absint( $received['post_id'] ) )
    781                         return $response;
     804        if ( ! $post_id = absint( $received['post_id'] ) )
     805            return $response;
    782806
    783                 if ( ! current_user_can('edit_post', $post_id) )
    784                         return $response;
     807        if ( ! current_user_can('edit_post', $post_id) )
     808            return $response;
    785809
    786                 if ( ( $user_id = wp_check_post_lock( $post_id ) ) && ( $user = get_userdata( $user_id ) ) ) {
    787                         $error = array(
    788                                 'text' => sprintf( __( '%s has taken over and is currently editing.' ), $user->display_name )
    789                         );
     810        if ( ( $user_id = wp_check_post_lock( $post_id ) ) && ( $user = get_userdata( $user_id ) ) ) {
     811            $error = array(
     812                'text' => sprintf( __( '%s has taken over and is currently editing.' ), $user->display_name )
     813            );
    790814
    791                         if ( $avatar = get_avatar( $user->ID, 64 ) ) {
    792                                 if ( preg_match( "|src='([^']+)'|", $avatar, $matches ) )
    793                                         $error['avatar_src'] = $matches[1];
    794                         }
     815            if ( $avatar = get_avatar( $user->ID, 64 ) ) {
     816                if ( preg_match( "|src='([^']+)'|", $avatar, $matches ) )
     817                    $error['avatar_src'] = $matches[1];
     818            }
    795819
    796                         $send['lock_error'] = $error;
    797                 } else {
    798                         if ( $new_lock = wp_set_post_lock( $post_id ) )
    799                                 $send['new_lock'] = implode( ':', $new_lock );
    800                 }
     820            $send['lock_error'] = $error;
     821        } else {
     822            if ( $new_lock = wp_set_post_lock( $post_id ) )
     823                $send['new_lock'] = implode( ':', $new_lock );
     824        }
    801825
    802                 $response['wp-refresh-post-lock'] = $send;
    803         }
     826        $response['wp-refresh-post-lock'] = $send;
     827    }
    804828
    805         return $response;
     829    return $response;
    806830}
    807831
    808832/**
    function wp_refresh_post_lock( $response, $data, $screen_id ) { 
    816840 * @return array The Heartbeat response.
    817841 */
    818842function wp_refresh_post_nonces( $response, $data, $screen_id ) {
    819         if ( array_key_exists( 'wp-refresh-post-nonces', $data ) ) {
    820                 $received = $data['wp-refresh-post-nonces'];
    821                 $response['wp-refresh-post-nonces'] = array( 'check' => 1 );
    822 
    823                 if ( ! $post_id = absint( $received['post_id'] ) ) {
    824                         return $response;
    825                 }
    826 
    827                 if ( ! current_user_can( 'edit_post', $post_id ) ) {
    828                         return $response;
    829                 }
    830 
    831                 $response['wp-refresh-post-nonces'] = array(
    832                         'replace' => array(
    833                                 'getpermalinknonce' => wp_create_nonce('getpermalink'),
    834                                 'samplepermalinknonce' => wp_create_nonce('samplepermalink'),
    835                                 'closedpostboxesnonce' => wp_create_nonce('closedpostboxes'),
    836                                 '_ajax_linking_nonce' => wp_create_nonce( 'internal-linking' ),
    837                                 '_wpnonce' => wp_create_nonce( 'update-post_' . $post_id ),
    838                         ),
    839                         'heartbeatNonce' => wp_create_nonce( 'heartbeat-nonce' ),
    840                 );
    841         }
    842 
    843         return $response;
     843    if ( array_key_exists( 'wp-refresh-post-nonces', $data ) ) {
     844        $received = $data['wp-refresh-post-nonces'];
     845        $response['wp-refresh-post-nonces'] = array( 'check' => 1 );
     846
     847        if ( ! $post_id = absint( $received['post_id'] ) ) {
     848            return $response;
     849        }
     850
     851        if ( ! current_user_can( 'edit_post', $post_id ) ) {
     852            return $response;
     853        }
     854
     855        $response['wp-refresh-post-nonces'] = array(
     856            'replace' => array(
     857                'getpermalinknonce' => wp_create_nonce('getpermalink'),
     858                'samplepermalinknonce' => wp_create_nonce('samplepermalink'),
     859                'closedpostboxesnonce' => wp_create_nonce('closedpostboxes'),
     860                '_ajax_linking_nonce' => wp_create_nonce( 'internal-linking' ),
     861                '_wpnonce' => wp_create_nonce( 'update-post_' . $post_id ),
     862            ),
     863            'heartbeatNonce' => wp_create_nonce( 'heartbeat-nonce' ),
     864        );
     865    }
     866
     867    return $response;
    844868}
    845869
    846870/**
    function wp_refresh_post_nonces( $response, $data, $screen_id ) { 
    854878 * @return array Filtered Heartbeat settings.
    855879 */
    856880function wp_heartbeat_set_suspension( $settings ) {
    857         global $pagenow;
     881    global $pagenow;
    858882
    859         if ( 'post.php' === $pagenow || 'post-new.php' === $pagenow ) {
    860                 $settings['suspension'] = 'disable';
    861         }
     883    if ( 'post.php' === $pagenow || 'post-new.php' === $pagenow ) {
     884        $settings['suspension'] = 'disable';
     885    }
    862886
    863         return $settings;
     887    return $settings;
    864888}
    865889
    866890/**
    function wp_heartbeat_set_suspension( $settings ) { 
    873897 * @return array The Heartbeat response.
    874898 */
    875899function heartbeat_autosave( $response, $data ) {
    876         if ( ! empty( $data['wp_autosave'] ) ) {
    877                 $saved = wp_autosave( $data['wp_autosave'] );
    878 
    879                 if ( is_wp_error( $saved ) ) {
    880                         $response['wp_autosave'] = array( 'success' => false, 'message' => $saved->get_error_message() );
    881                 } elseif ( empty( $saved ) ) {
    882                         $response['wp_autosave'] = array( 'success' => false, 'message' => __( 'Error while saving.' ) );
    883                 } else {
    884                         /* translators: draft saved date format, see https://secure.php.net/date */
    885                         $draft_saved_date_format = __( 'g:i:s a' );
    886                         /* translators: %s: date and time */
    887                         $response['wp_autosave'] = array( 'success' => true, 'message' => sprintf( __( 'Draft saved at %s.' ), date_i18n( $draft_saved_date_format ) ) );
    888                 }
    889         }
    890 
    891         return $response;
     900    if ( ! empty( $data['wp_autosave'] ) ) {
     901        $saved = wp_autosave( $data['wp_autosave'] );
     902
     903        if ( is_wp_error( $saved ) ) {
     904            $response['wp_autosave'] = array( 'success' => false, 'message' => $saved->get_error_message() );
     905        } elseif ( empty( $saved ) ) {
     906            $response['wp_autosave'] = array( 'success' => false, 'message' => __( 'Error while saving.' ) );
     907        } else {
     908            /* translators: draft saved date format, see https://secure.php.net/date */
     909            $draft_saved_date_format = __( 'g:i:s a' );
     910            /* translators: %s: date and time */
     911            $response['wp_autosave'] = array( 'success' => true, 'message' => sprintf( __( 'Draft saved at %s.' ), date_i18n( $draft_saved_date_format ) ) );
     912        }
     913    }
     914
     915    return $response;
    892916}
    893917
    894918/**
    function heartbeat_autosave( $response, $data ) { 
    900924 * @since 4.2.0
    901925 */
    902926function wp_admin_canonical_url() {
    903         $removable_query_args = wp_removable_query_args();
    904 
    905         if ( empty( $removable_query_args ) ) {
    906                 return;
    907         }
    908 
    909         // Ensure we're using an absolute URL.
    910         $current_url  = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
    911         $filtered_url = remove_query_arg( $removable_query_args, $current_url );
    912         ?>
    913         <link id="wp-admin-canonical" rel="canonical" href="<?php echo esc_url( $filtered_url ); ?>" />
    914         <script>
    915                 if ( window.history.replaceState ) {
    916                         window.history.replaceState( null, null, document.getElementById( 'wp-admin-canonical' ).href + window.location.hash );
    917                 }
    918         </script>
     927    $removable_query_args = wp_removable_query_args();
     928
     929    if ( empty( $removable_query_args ) ) {
     930        return;
     931    }
     932
     933    // Ensure we're using an absolute URL.
     934    $current_url  = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
     935    $filtered_url = remove_query_arg( $removable_query_args, $current_url );
     936    ?>
     937    <link id="wp-admin-canonical" rel="canonical" href="<?php echo esc_url( $filtered_url ); ?>" />
     938    <script>
     939        if ( window.history.replaceState ) {
     940            window.history.replaceState( null, null, document.getElementById( 'wp-admin-canonical' ).href + window.location.hash );
     941        }
     942    </script>
    919943<?php
    920944}
    921945
    function wp_admin_canonical_url() { 
    928952 * @since 4.6.0
    929953 */
    930954function wp_page_reload_on_back_button_js() {
    931         ?>
    932         <script>
    933                 if ( typeof performance !== 'undefined' && performance.navigation && performance.navigation.type === 2 ) {
    934                         document.location.reload( true );
    935                 }
    936         </script>
    937         <?php
     955    ?>
     956    <script>
     957        if ( typeof performance !== 'undefined' && performance.navigation && performance.navigation.type === 2 ) {
     958            document.location.reload( true );
     959        }
     960    </script>
     961    <?php
    938962}
  • src/wp-admin/link-add.php

    diff --git a/src/wp-admin/link-add.php b/src/wp-admin/link-add.php
    index 423c6680e5..245b62cbbd 100644
    a b  
    1010require_once( dirname( __FILE__ ) . '/admin.php' );
    1111
    1212if ( ! current_user_can('manage_links') )
    13         wp_die(__('Sorry, you are not allowed to add links to this site.'));
     13    wp_die(__('Sorry, you are not allowed to add links to this site.'));
    1414
    1515$title = __('Add New Link');
    1616$parent_file = 'link-manager.php';
    1717
    18 wp_reset_vars( array('action', 'cat_id', 'link_id' ) );
     18$action = wp_assign_request_var('action');
     19$cat_id = wp_assign_request_var('cat_id');
     20$link_id = wp_assign_request_var('link_id');
    1921
    2022wp_enqueue_script('link');
    2123wp_enqueue_script('xfn');
    2224
    2325if ( wp_is_mobile() )
    24         wp_enqueue_script( 'jquery-touch-punch' );
     26    wp_enqueue_script( 'jquery-touch-punch' );
    2527
    2628$link = get_default_link_to_edit();
    2729include( ABSPATH . 'wp-admin/edit-link-form.php' );
  • src/wp-admin/link.php

    diff --git a/src/wp-admin/link.php b/src/wp-admin/link.php
    index bcfe578fb0..6100401ec0 100644
    a b  
    1212/** Load WordPress Administration Bootstrap */
    1313require_once( dirname( __FILE__ ) . '/admin.php' );
    1414
    15 wp_reset_vars( array( 'action', 'cat_id', 'link_id' ) );
     15$action = wp_assign_request_var('action');
     16$cat_id = wp_assign_request_var('cat_id');
     17$link_id = wp_assign_request_var('link_id');
    1618
    1719if ( ! current_user_can('manage_links') )
    18         wp_link_manager_disabled_message();
     20    wp_link_manager_disabled_message();
    1921
    2022if ( !empty($_POST['deletebookmarks']) )
    21         $action = 'deletebookmarks';
     23    $action = 'deletebookmarks';
    2224if ( !empty($_POST['move']) )
    23         $action = 'move';
     25    $action = 'move';
    2426if ( !empty($_POST['linkcheck']) )
    25         $linkcheck = $_POST['linkcheck'];
     27    $linkcheck = $_POST['linkcheck'];
    2628
    2729$this_file = admin_url('link-manager.php');
    2830
    2931switch ($action) {
    30         case 'deletebookmarks' :
    31                 check_admin_referer('bulk-bookmarks');
     32    case 'deletebookmarks' :
     33        check_admin_referer('bulk-bookmarks');
    3234
    33                 // For each link id (in $linkcheck[]) change category to selected value.
    34                 if (count($linkcheck) == 0) {
    35                         wp_redirect($this_file);
    36                         exit;
    37                 }
     35        // For each link id (in $linkcheck[]) change category to selected value.
     36        if (count($linkcheck) == 0) {
     37            wp_redirect($this_file);
     38            exit;
     39        }
    3840
    39                 $deleted = 0;
    40                 foreach ($linkcheck as $link_id) {
    41                         $link_id = (int) $link_id;
     41        $deleted = 0;
     42        foreach ($linkcheck as $link_id) {
     43            $link_id = (int) $link_id;
    4244
    43                         if ( wp_delete_link($link_id) )
    44                                 $deleted++;
    45                 }
     45            if ( wp_delete_link($link_id) )
     46                $deleted++;
     47        }
    4648
    47                 wp_redirect("$this_file?deleted=$deleted");
    48                 exit;
     49        wp_redirect("$this_file?deleted=$deleted");
     50        exit;
    4951
    50         case 'move' :
    51                 check_admin_referer('bulk-bookmarks');
     52    case 'move' :
     53        check_admin_referer('bulk-bookmarks');
    5254
    53                 // For each link id (in $linkcheck[]) change category to selected value.
    54                 if (count($linkcheck) == 0) {
    55                         wp_redirect($this_file);
    56                         exit;
    57                 }
    58                 $all_links = join(',', $linkcheck);
    59                 /*
    60                 * Should now have an array of links we can change:
    61                 *     $q = $wpdb->query("update $wpdb->links SET link_category='$category' WHERE link_id IN ($all_links)");
    62                 */
     55        // For each link id (in $linkcheck[]) change category to selected value.
     56        if (count($linkcheck) == 0) {
     57            wp_redirect($this_file);
     58            exit;
     59        }
     60        $all_links = join(',', $linkcheck);
     61        /*
     62        * Should now have an array of links we can change:
     63        *     $q = $wpdb->query("update $wpdb->links SET link_category='$category' WHERE link_id IN ($all_links)");
     64        */
    6365
    64                 wp_redirect($this_file);
    65                 exit;
     66        wp_redirect($this_file);
     67        exit;
    6668
    67         case 'add' :
    68                 check_admin_referer('add-bookmark');
     69    case 'add' :
     70        check_admin_referer('add-bookmark');
    6971
    70                 $redir = wp_get_referer();
    71                 if ( add_link() )
    72                         $redir = add_query_arg( 'added', 'true', $redir );
     72        $redir = wp_get_referer();
     73        if ( add_link() )
     74            $redir = add_query_arg( 'added', 'true', $redir );
    7375
    74                 wp_redirect( $redir );
    75                 exit;
     76        wp_redirect( $redir );
     77        exit;
    7678
    77         case 'save' :
    78                 $link_id = (int) $_POST['link_id'];
    79                 check_admin_referer('update-bookmark_' . $link_id);
     79    case 'save' :
     80        $link_id = (int) $_POST['link_id'];
     81        check_admin_referer('update-bookmark_' . $link_id);
    8082
    81                 edit_link($link_id);
     83        edit_link($link_id);
    8284
    83                 wp_redirect($this_file);
    84                 exit;
     85        wp_redirect($this_file);
     86        exit;
    8587
    86         case 'delete' :
    87                 $link_id = (int) $_GET['link_id'];
    88                 check_admin_referer('delete-bookmark_' . $link_id);
     88    case 'delete' :
     89        $link_id = (int) $_GET['link_id'];
     90        check_admin_referer('delete-bookmark_' . $link_id);
    8991
    90                 wp_delete_link($link_id);
     92        wp_delete_link($link_id);
    9193
    92                 wp_redirect($this_file);
    93                 exit;
     94        wp_redirect($this_file);
     95        exit;
    9496
    95         case 'edit' :
    96                 wp_enqueue_script('link');
    97                 wp_enqueue_script('xfn');
     97    case 'edit' :
     98        wp_enqueue_script('link');
     99        wp_enqueue_script('xfn');
    98100
    99                 if ( wp_is_mobile() )
    100                         wp_enqueue_script( 'jquery-touch-punch' );
     101        if ( wp_is_mobile() )
     102            wp_enqueue_script( 'jquery-touch-punch' );
    101103
    102                 $parent_file = 'link-manager.php';
    103                 $submenu_file = 'link-manager.php';
    104                 $title = __('Edit Link');
     104        $parent_file = 'link-manager.php';
     105        $submenu_file = 'link-manager.php';
     106        $title = __('Edit Link');
    105107
    106                 $link_id = (int) $_GET['link_id'];
     108        $link_id = (int) $_GET['link_id'];
    107109
    108                 if (!$link = get_link_to_edit($link_id))
    109                         wp_die(__('Link not found.'));
     110        if (!$link = get_link_to_edit($link_id))
     111            wp_die(__('Link not found.'));
    110112
    111                 include( ABSPATH . 'wp-admin/edit-link-form.php' );
    112                 include( ABSPATH . 'wp-admin/admin-footer.php' );
    113                 break;
     113        include( ABSPATH . 'wp-admin/edit-link-form.php' );
     114        include( ABSPATH . 'wp-admin/admin-footer.php' );
     115        break;
    114116
    115         default :
    116                 break;
     117    default :
     118        break;
    117119}
  • src/wp-admin/media.php

    diff --git a/src/wp-admin/media.php b/src/wp-admin/media.php
    index be3cecad98..e89bb03b82 100644
    a b require_once( dirname( __FILE__ ) . '/admin.php' ); 
    1212$parent_file = 'upload.php';
    1313$submenu_file = 'upload.php';
    1414
    15 wp_reset_vars(array('action'));
     15$action = wp_assign_request_var('action');
    1616
    1717switch ( $action ) {
    1818case 'editattachment' :
    19         $attachment_id = (int) $_POST['attachment_id'];
    20         check_admin_referer('media-form');
    21 
    22         if ( !current_user_can('edit_post', $attachment_id) )
    23                 wp_die ( __('Sorry, you are not allowed to edit this attachment.') );
    24 
    25         $errors = media_upload_form_handler();
    26 
    27         if ( empty($errors) ) {
    28                 $location = 'media.php';
    29                 if ( $referer = wp_get_original_referer() ) {
    30                         if ( false !== strpos($referer, 'upload.php') || ( url_to_postid($referer) == $attachment_id )  )
    31                                 $location = $referer;
    32                 }
    33                 if ( false !== strpos($location, 'upload.php') ) {
    34                         $location = remove_query_arg('message', $location);
    35                         $location = add_query_arg('posted',     $attachment_id, $location);
    36                 } elseif ( false !== strpos($location, 'media.php') ) {
    37                         $location = add_query_arg('message', 'updated', $location);
    38                 }
    39                 wp_redirect($location);
    40                 exit;
    41         }
    42 
    43         // No break.
     19    $attachment_id = (int) $_POST['attachment_id'];
     20    check_admin_referer('media-form');
     21
     22    if ( !current_user_can('edit_post', $attachment_id) )
     23        wp_die ( __('Sorry, you are not allowed to edit this attachment.') );
     24
     25    $errors = media_upload_form_handler();
     26
     27    if ( empty($errors) ) {
     28        $location = 'media.php';
     29        if ( $referer = wp_get_original_referer() ) {
     30            if ( false !== strpos($referer, 'upload.php') || ( url_to_postid($referer) == $attachment_id )  )
     31                $location = $referer;
     32        }
     33        if ( false !== strpos($location, 'upload.php') ) {
     34            $location = remove_query_arg('message', $location);
     35            $location = add_query_arg('posted', $attachment_id, $location);
     36        } elseif ( false !== strpos($location, 'media.php') ) {
     37            $location = add_query_arg('message', 'updated', $location);
     38        }
     39        wp_redirect($location);
     40        exit;
     41    }
     42
     43    // No break.
    4444case 'edit' :
    45         $title = __('Edit Media');
    46 
    47         if ( empty($errors) )
    48                 $errors = null;
    49 
    50         if ( empty( $_GET['attachment_id'] ) ) {
    51                 wp_redirect( admin_url('upload.php') );
    52                 exit();
    53         }
    54         $att_id = (int) $_GET['attachment_id'];
    55 
    56         if ( !current_user_can('edit_post', $att_id) )
    57                 wp_die ( __('Sorry, you are not allowed to edit this attachment.') );
    58 
    59         $att = get_post($att_id);
    60 
    61         if ( empty($att->ID) ) wp_die( __('You attempted to edit an attachment that doesn&#8217;t exist. Perhaps it was deleted?') );
    62         if ( 'attachment' !== $att->post_type ) wp_die( __('You attempted to edit an item that isn&#8217;t an attachment. Please go back and try again.') );
    63         if ( $att->post_status == 'trash' ) wp_die( __('You can&#8217;t edit this attachment because it is in the Trash. Please move it out of the Trash and try again.') );
    64 
    65         add_filter('attachment_fields_to_edit', 'media_single_attachment_fields_to_edit', 10, 2);
    66 
    67         wp_enqueue_script( 'wp-ajax-response' );
    68         wp_enqueue_script('image-edit');
    69         wp_enqueue_style('imgareaselect');
    70 
    71         get_current_screen()->add_help_tab( array(
    72                 'id'      => 'overview',
    73                 'title'   => __('Overview'),
    74                 'content' =>
    75                         '<p>' . __('This screen allows you to edit five fields for metadata in a file within the media library.') . '</p>' .
    76                         '<p>' . __('For images only, you can click on Edit Image under the thumbnail to expand out an inline image editor with icons for cropping, rotating, or flipping the image as well as for undoing and redoing. The boxes on the right give you more options for scaling the image, for cropping it, and for cropping the thumbnail in a different way than you crop the original image. You can click on Help in those boxes to get more information.') . '</p>' .
    77                         '<p>' . __('Note that you crop the image by clicking on it (the Crop icon is already selected) and dragging the cropping frame to select the desired part. Then click Save to retain the cropping.') . '</p>' .
    78                         '<p>' . __('Remember to click Update Media to save metadata entered or changed.') . '</p>'
    79         ) );
    80 
    81         get_current_screen()->set_help_sidebar(
    82         '<p><strong>' . __('For more information:') . '</strong></p>' .
    83         '<p>' . __('<a href="https://codex.wordpress.org/Media_Add_New_Screen#Edit_Media">Documentation on Edit Media</a>') . '</p>' .
    84         '<p>' . __('<a href="https://wordpress.org/support/">Support Forums</a>') . '</p>'
    85         );
    86 
    87         require( ABSPATH . 'wp-admin/admin-header.php' );
    88 
    89         $parent_file = 'upload.php';
    90         $message = '';
    91         $class = '';
    92         if ( isset($_GET['message']) ) {
    93                 switch ( $_GET['message'] ) {
    94                         case 'updated' :
    95                                 $message = __('Media file updated.');
    96                                 $class = 'updated';
    97                                 break;
    98                 }
    99         }
    100         if ( $message )
    101                 echo "<div id='message' class='$class'><p>$message</p></div>\n";
     45    $title = __('Edit Media');
     46
     47    if ( empty($errors) )
     48        $errors = null;
     49
     50    if ( empty( $_GET['attachment_id'] ) ) {
     51        wp_redirect( admin_url('upload.php') );
     52        exit();
     53    }
     54    $att_id = (int) $_GET['attachment_id'];
     55
     56    if ( !current_user_can('edit_post', $att_id) )
     57        wp_die ( __('Sorry, you are not allowed to edit this attachment.') );
     58
     59    $att = get_post($att_id);
     60
     61    if ( empty($att->ID) ) wp_die( __('You attempted to edit an attachment that doesn&#8217;t exist. Perhaps it was deleted?') );
     62    if ( 'attachment' !== $att->post_type ) wp_die( __('You attempted to edit an item that isn&#8217;t an attachment. Please go back and try again.') );
     63    if ( $att->post_status == 'trash' ) wp_die( __('You can&#8217;t edit this attachment because it is in the Trash. Please move it out of the Trash and try again.') );
     64
     65    add_filter('attachment_fields_to_edit', 'media_single_attachment_fields_to_edit', 10, 2);
     66
     67    wp_enqueue_script( 'wp-ajax-response' );
     68    wp_enqueue_script('image-edit');
     69    wp_enqueue_style('imgareaselect');
     70
     71    get_current_screen()->add_help_tab( array(
     72        'id'      => 'overview',
     73        'title'   => __('Overview'),
     74        'content' =>
     75            '<p>' . __('This screen allows you to edit five fields for metadata in a file within the media library.') . '</p>' .
     76            '<p>' . __('For images only, you can click on Edit Image under the thumbnail to expand out an inline image editor with icons for cropping, rotating, or flipping the image as well as for undoing and redoing. The boxes on the right give you more options for scaling the image, for cropping it, and for cropping the thumbnail in a different way than you crop the original image. You can click on Help in those boxes to get more information.') . '</p>' .
     77            '<p>' . __('Note that you crop the image by clicking on it (the Crop icon is already selected) and dragging the cropping frame to select the desired part. Then click Save to retain the cropping.') . '</p>' .
     78            '<p>' . __('Remember to click Update Media to save metadata entered or changed.') . '</p>'
     79    ) );
     80
     81    get_current_screen()->set_help_sidebar(
     82    '<p><strong>' . __('For more information:') . '</strong></p>' .
     83    '<p>' . __('<a href="https://codex.wordpress.org/Media_Add_New_Screen#Edit_Media">Documentation on Edit Media</a>') . '</p>' .
     84    '<p>' . __('<a href="https://wordpress.org/support/">Support Forums</a>') . '</p>'
     85    );
     86
     87    require( ABSPATH . 'wp-admin/admin-header.php' );
     88
     89    $parent_file = 'upload.php';
     90    $message = '';
     91    $class = '';
     92    if ( isset($_GET['message']) ) {
     93        switch ( $_GET['message'] ) {
     94            case 'updated' :
     95                $message = __('Media file updated.');
     96                $class = 'updated';
     97                break;
     98        }
     99    }
     100    if ( $message )
     101        echo "<div id='message' class='$class'><p>$message</p></div>\n";
    102102
    103103?>
    104104
    echo esc_html( $title ); 
    109109
    110110<?php
    111111if ( current_user_can( 'upload_files' ) ) { ?>
    112         <a href="media-new.php" class="page-title-action"><?php echo esc_html_x('Add New', 'file'); ?></a>
     112    <a href="media-new.php" class="page-title-action"><?php echo esc_html_x('Add New', 'file'); ?></a>
    113113<?php } ?>
    114114
    115115<hr class="wp-header-end">
    if ( current_user_can( 'upload_files' ) ) { ?> 
    138138
    139139<?php
    140140
    141         require( ABSPATH . 'wp-admin/admin-footer.php' );
     141    require( ABSPATH . 'wp-admin/admin-footer.php' );
    142142
    143         exit;
     143    exit;
    144144
    145145default:
    146         wp_redirect( admin_url('upload.php') );
    147         exit;
     146    wp_redirect( admin_url('upload.php') );
     147    exit;
    148148
    149149}
  • src/wp-admin/options-head.php

    diff --git a/src/wp-admin/options-head.php b/src/wp-admin/options-head.php
    index bee3ae7e67..848733eda1 100644
    a b  
    88 * @subpackage Administration
    99 */
    1010
    11 wp_reset_vars( array( 'action' ) );
     11$action = wp_assign_request_var('action');
    1212
    1313if ( isset( $_GET['updated'] ) && isset( $_GET['page'] ) ) {
    14         // For back-compat with plugins that don't use the Settings API and just set updated=1 in the redirect.
    15         add_settings_error('general', 'settings_updated', __('Settings saved.'), 'updated');
     14    // For back-compat with plugins that don't use the Settings API and just set updated=1 in the redirect.
     15    add_settings_error('general', 'settings_updated', __('Settings saved.'), 'updated');
    1616}
    1717
    1818settings_errors();
  • src/wp-admin/options.php

    diff --git a/src/wp-admin/options.php b/src/wp-admin/options.php
    index d2e1c0374f..7f2c7a5129 100644
    a b $title = __('Settings'); 
    2222$this_file = 'options.php';
    2323$parent_file = 'options-general.php';
    2424
    25 wp_reset_vars(array('action', 'option_page'));
     25$action = wp_assign_request_var('action');
     26$option_page = wp_assign_request_var('option_page');
    2627
    2728$capability = 'manage_options';
    2829
    2930// This is for back compat and will eventually be removed.
    3031if ( empty($option_page) ) {
    31         $option_page = 'options';
     32    $option_page = 'options';
    3233} else {
    3334
    34         /**
    35         * Filters the capability required when using the Settings API.
    36         *
    37         * By default, the options groups for all registered settings require the manage_options capability.
    38         * This filter is required to change the capability required for a certain options page.
    39         *
    40         * @since 3.2.0
    41         *
    42         * @param string $capability The capability used for the page, which is manage_options by default.
    43         */
    44         $capability = apply_filters( "option_page_capability_{$option_page}", $capability );
     35    /**
     36    * Filters the capability required when using the Settings API.
     37    *
     38    * By default, the options groups for all registered settings require the manage_options capability.
     39    * This filter is required to change the capability required for a certain options page.
     40    *
     41    * @since 3.2.0
     42    *
     43    * @param string $capability The capability used for the page, which is manage_options by default.
     44    */
     45    $capability = apply_filters( "option_page_capability_{$option_page}", $capability );
    4546}
    4647
    4748if ( ! current_user_can( $capability ) ) {
    48         wp_die(
    49                 '<h1>' . __( 'Cheatin&#8217; uh?' ) . '</h1>' .
    50                 '<p>' . __( 'Sorry, you are not allowed to manage these options.' ) . '</p>',
    51                 403
    52         );
     49    wp_die(
     50        '<h1>' . __( 'Cheatin&#8217; uh?' ) . '</h1>' .
     51        '<p>' . __( 'Sorry, you are not allowed to manage these options.' ) . '</p>',
     52        403
     53    );
    5354}
    5455
    5556// Handle admin email change requests
    5657if ( is_multisite() ) {
    57         if ( ! empty($_GET[ 'adminhash' ] ) ) {
    58                 $new_admin_details = get_option( 'adminhash' );
    59                 $redirect = 'options-general.php?updated=false';
    60                 if ( is_array( $new_admin_details ) && hash_equals( $new_admin_details[ 'hash' ], $_GET[ 'adminhash' ] ) && !empty($new_admin_details[ 'newemail' ]) ) {
    61                         update_option( 'admin_email', $new_admin_details[ 'newemail' ] );
    62                         delete_option( 'adminhash' );
    63                         delete_option( 'new_admin_email' );
    64                         $redirect = 'options-general.php?updated=true';
    65                 }
    66                 wp_redirect( admin_url( $redirect ) );
    67                 exit;
    68         } elseif ( ! empty( $_GET['dismiss'] ) && 'new_admin_email' == $_GET['dismiss'] ) {
    69                 check_admin_referer( 'dismiss-' . get_current_blog_id() . '-new_admin_email' );
    70                 delete_option( 'adminhash' );
    71                 delete_option( 'new_admin_email' );
    72                 wp_redirect( admin_url( 'options-general.php?updated=true' ) );
    73                 exit;
    74         }
     58    if ( ! empty($_GET[ 'adminhash' ] ) ) {
     59        $new_admin_details = get_option( 'adminhash' );
     60        $redirect = 'options-general.php?updated=false';
     61        if ( is_array( $new_admin_details ) && hash_equals( $new_admin_details[ 'hash' ], $_GET[ 'adminhash' ] ) && !empty($new_admin_details[ 'newemail' ]) ) {
     62            update_option( 'admin_email', $new_admin_details[ 'newemail' ] );
     63            delete_option( 'adminhash' );
     64            delete_option( 'new_admin_email' );
     65            $redirect = 'options-general.php?updated=true';
     66        }
     67        wp_redirect( admin_url( $redirect ) );
     68        exit;
     69    } elseif ( ! empty( $_GET['dismiss'] ) && 'new_admin_email' == $_GET['dismiss'] ) {
     70        check_admin_referer( 'dismiss-' . get_current_blog_id() . '-new_admin_email' );
     71        delete_option( 'adminhash' );
     72        delete_option( 'new_admin_email' );
     73        wp_redirect( admin_url( 'options-general.php?updated=true' ) );
     74        exit;
     75    }
    7576}
    7677
    7778if ( is_multisite() && ! current_user_can( 'manage_network_options' ) && 'update' != $action ) {
    78         wp_die(
    79                 '<h1>' . __( 'Cheatin&#8217; uh?' ) . '</h1>' .
    80                 '<p>' . __( 'Sorry, you are not allowed to delete these items.' ) . '</p>',
    81                 403
    82         );
     79    wp_die(
     80        '<h1>' . __( 'Cheatin&#8217; uh?' ) . '</h1>' .
     81        '<p>' . __( 'Sorry, you are not allowed to delete these items.' ) . '</p>',
     82        403
     83    );
    8384}
    8485
    8586$whitelist_options = array(
    86         'general' => array( 'blogname', 'blogdescription', 'gmt_offset', 'date_format', 'time_format', 'start_of_week', 'timezone_string', 'WPLANG' ),
    87         'discussion' => array( 'default_pingback_flag', 'default_ping_status', 'default_comment_status', 'comments_notify', 'moderation_notify', 'comment_moderation', 'require_name_email', 'comment_whitelist', 'comment_max_links', 'moderation_keys', 'blacklist_keys', 'show_avatars', 'avatar_rating', 'avatar_default', 'close_comments_for_old_posts', 'close_comments_days_old', 'thread_comments', 'thread_comments_depth', 'page_comments', 'comments_per_page', 'default_comments_page', 'comment_order', 'comment_registration' ),
    88         'media' => array( 'thumbnail_size_w', 'thumbnail_size_h', 'thumbnail_crop', 'medium_size_w', 'medium_size_h', 'large_size_w', 'large_size_h', 'image_default_size', 'image_default_align', 'image_default_link_type' ),
    89         'reading' => array( 'posts_per_page', 'posts_per_rss', 'rss_use_excerpt', 'show_on_front', 'page_on_front', 'page_for_posts', 'blog_public' ),
    90         'writing' => array( 'default_category', 'default_email_category', 'default_link_category', 'default_post_format' )
     87    'general' => array( 'blogname', 'blogdescription', 'gmt_offset', 'date_format', 'time_format', 'start_of_week', 'timezone_string', 'WPLANG' ),
     88    'discussion' => array( 'default_pingback_flag', 'default_ping_status', 'default_comment_status', 'comments_notify', 'moderation_notify', 'comment_moderation', 'require_name_email', 'comment_whitelist', 'comment_max_links', 'moderation_keys', 'blacklist_keys', 'show_avatars', 'avatar_rating', 'avatar_default', 'close_comments_for_old_posts', 'close_comments_days_old', 'thread_comments', 'thread_comments_depth', 'page_comments', 'comments_per_page', 'default_comments_page', 'comment_order', 'comment_registration' ),
     89    'media' => array( 'thumbnail_size_w', 'thumbnail_size_h', 'thumbnail_crop', 'medium_size_w', 'medium_size_h', 'large_size_w', 'large_size_h', 'image_default_size', 'image_default_align', 'image_default_link_type' ),
     90    'reading' => array( 'posts_per_page', 'posts_per_rss', 'rss_use_excerpt', 'show_on_front', 'page_on_front', 'page_for_posts', 'blog_public' ),
     91    'writing' => array( 'default_category', 'default_email_category', 'default_link_category', 'default_post_format' )
    9192);
    9293$whitelist_options['misc'] = $whitelist_options['options'] = $whitelist_options['privacy'] = array();
    9394
    9495$mail_options = array('mailserver_url', 'mailserver_port', 'mailserver_login', 'mailserver_pass');
    9596
    9697if ( ! in_array( get_option( 'blog_charset' ), array( 'utf8', 'utf-8', 'UTF8', 'UTF-8' ) ) )
    97         $whitelist_options['reading'][] = 'blog_charset';
     98    $whitelist_options['reading'][] = 'blog_charset';
    9899
    99100if ( get_site_option( 'initial_db_version' ) < 32453 ) {
    100         $whitelist_options['writing'][] = 'use_smilies';
    101         $whitelist_options['writing'][] = 'use_balanceTags';
     101    $whitelist_options['writing'][] = 'use_smilies';
     102    $whitelist_options['writing'][] = 'use_balanceTags';
    102103}
    103104
    104105if ( !is_multisite() ) {
    105         if ( !defined( 'WP_SITEURL' ) )
    106                 $whitelist_options['general'][] = 'siteurl';
    107         if ( !defined( 'WP_HOME' ) )
    108                 $whitelist_options['general'][] = 'home';
     106    if ( !defined( 'WP_SITEURL' ) )
     107        $whitelist_options['general'][] = 'siteurl';
     108    if ( !defined( 'WP_HOME' ) )
     109        $whitelist_options['general'][] = 'home';
    109110
    110         $whitelist_options['general'][] = 'admin_email';
    111         $whitelist_options['general'][] = 'users_can_register';
    112         $whitelist_options['general'][] = 'default_role';
     111    $whitelist_options['general'][] = 'admin_email';
     112    $whitelist_options['general'][] = 'users_can_register';
     113    $whitelist_options['general'][] = 'default_role';
    113114
    114         $whitelist_options['writing'] = array_merge($whitelist_options['writing'], $mail_options);
    115         $whitelist_options['writing'][] = 'ping_sites';
     115    $whitelist_options['writing'] = array_merge($whitelist_options['writing'], $mail_options);
     116    $whitelist_options['writing'][] = 'ping_sites';
    116117
    117         $whitelist_options['media'][] = 'uploads_use_yearmonth_folders';
     118    $whitelist_options['media'][] = 'uploads_use_yearmonth_folders';
    118119
    119         // If upload_url_path and upload_path are both default values, they're locked.
    120         if ( get_option( 'upload_url_path' ) || ( get_option('upload_path') != 'wp-content/uploads' && get_option('upload_path') ) ) {
    121                 $whitelist_options['media'][] = 'upload_path';
    122                 $whitelist_options['media'][] = 'upload_url_path';
    123         }
     120    // If upload_url_path and upload_path are both default values, they're locked.
     121    if ( get_option( 'upload_url_path' ) || ( get_option('upload_path') != 'wp-content/uploads' && get_option('upload_path') ) ) {
     122        $whitelist_options['media'][] = 'upload_path';
     123        $whitelist_options['media'][] = 'upload_url_path';
     124    }
    124125} else {
    125         $whitelist_options['general'][] = 'new_admin_email';
    126 
    127         /**
    128         * Filters whether the post-by-email functionality is enabled.
    129         *
    130         * @since 3.0.0
    131         *
    132         * @param bool $enabled Whether post-by-email configuration is enabled. Default true.
    133         */
    134         if ( apply_filters( 'enable_post_by_email_configuration', true ) )
    135                 $whitelist_options['writing'] = array_merge($whitelist_options['writing'], $mail_options);
     126    $whitelist_options['general'][] = 'new_admin_email';
     127
     128    /**
     129    * Filters whether the post-by-email functionality is enabled.
     130    *
     131    * @since 3.0.0
     132    *
     133    * @param bool $enabled Whether post-by-email configuration is enabled. Default true.
     134    */
     135    if ( apply_filters( 'enable_post_by_email_configuration', true ) )
     136        $whitelist_options['writing'] = array_merge($whitelist_options['writing'], $mail_options);
    136137}
    137138
    138139/**
    $whitelist_options = apply_filters( 'whitelist_options', $whitelist_options ); 
    148149 * If $_GET['action'] == 'update' we are saving settings sent from a settings page
    149150 */
    150151if ( 'update' == $action ) {
    151         if ( 'options' == $option_page && !isset( $_POST['option_page'] ) ) { // This is for back compat and will eventually be removed.
    152                 $unregistered = true;
    153                 check_admin_referer( 'update-options' );
    154         } else {
    155                 $unregistered = false;
    156                 check_admin_referer( $option_page . '-options' );
    157         }
    158 
    159         if ( !isset( $whitelist_options[ $option_page ] ) )
    160                 wp_die( __( '<strong>ERROR</strong>: options page not found.' ) );
    161 
    162         if ( 'options' == $option_page ) {
    163                 if ( is_multisite() && ! current_user_can( 'manage_network_options' ) ) {
    164                         wp_die( __( 'Sorry, you are not allowed to modify unregistered settings for this site.' ) );
    165                 }
    166                 $options = explode( ',', wp_unslash( $_POST[ 'page_options' ] ) );
    167         } else {
    168                 $options = $whitelist_options[ $option_page ];
    169         }
    170 
    171         if ( 'general' == $option_page ) {
    172                 // Handle custom date/time formats.
    173                 if ( !empty($_POST['date_format']) && isset($_POST['date_format_custom']) && '\c\u\s\t\o\m' == wp_unslash( $_POST['date_format'] ) )
    174                         $_POST['date_format'] = $_POST['date_format_custom'];
    175                 if ( !empty($_POST['time_format']) && isset($_POST['time_format_custom']) && '\c\u\s\t\o\m' == wp_unslash( $_POST['time_format'] ) )
    176                         $_POST['time_format'] = $_POST['time_format_custom'];
    177                 // Map UTC+- timezones to gmt_offsets and set timezone_string to empty.
    178                 if ( !empty($_POST['timezone_string']) && preg_match('/^UTC[+-]/', $_POST['timezone_string']) ) {
    179                         $_POST['gmt_offset'] = $_POST['timezone_string'];
    180                         $_POST['gmt_offset'] = preg_replace('/UTC\+?/', '', $_POST['gmt_offset']);
    181                         $_POST['timezone_string'] = '';
    182                 }
    183 
    184                 // Handle translation install.
    185                 if ( ! empty( $_POST['WPLANG'] ) && ( ! is_multisite() || is_super_admin() ) ) { // @todo: Skip if already installed
    186                         require_once( ABSPATH . 'wp-admin/includes/translation-install.php' );
    187 
    188                         if ( wp_can_install_language_pack() ) {
    189                                 $language = wp_download_language_pack( $_POST['WPLANG'] );
    190                                 if ( $language ) {
    191                                         $_POST['WPLANG'] = $language;
    192                                 }
    193                         }
    194                 }
    195         }
    196 
    197         if ( $options ) {
    198                 $user_language_old = get_user_locale();
    199 
    200                 foreach ( $options as $option ) {
    201                         if ( $unregistered ) {
    202                                 _deprecated_argument( 'options.php', '2.7.0',
    203                                         sprintf(
    204                                                 /* translators: %s: the option/setting */
    205                                                 __( 'The %s setting is unregistered. Unregistered settings are deprecated. See https://codex.wordpress.org/Settings_API' ),
    206                                                 '<code>' . $option . '</code>'
    207                                         )
    208                                 );
    209                         }
    210 
    211                         $option = trim( $option );
    212                         $value = null;
    213                         if ( isset( $_POST[ $option ] ) ) {
    214                                 $value = $_POST[ $option ];
    215                                 if ( ! is_array( $value ) ) {
    216                                         $value = trim( $value );
    217                                 }
    218                                 $value = wp_unslash( $value );
    219                         }
    220                         update_option( $option, $value );
    221                 }
    222 
    223                 /*
    224                 * Switch translation in case WPLANG was changed.
    225                 * The global $locale is used in get_locale() which is
    226                 * used as a fallback in get_user_locale().
    227                 */
    228                 unset( $GLOBALS['locale'] );
    229                 $user_language_new = get_user_locale();
    230                 if ( $user_language_old !== $user_language_new  ) {
    231                         load_default_textdomain( $user_language_new );
    232                 }
    233         }
    234 
    235         /**
    236         * Handle settings errors and return to options page
    237         */
    238         // If no settings errors were registered add a general 'updated' message.
    239         if ( !count( get_settings_errors() ) )
    240                 add_settings_error('general', 'settings_updated', __('Settings saved.'), 'updated');
    241         set_transient('settings_errors', get_settings_errors(), 30);
    242 
    243         /**
    244         * Redirect back to the settings page that was submitted
    245         */
    246         $goback = add_query_arg( 'settings-updated', 'true',  wp_get_referer() );
    247         wp_redirect( $goback );
    248         exit;
     152    if ( 'options' == $option_page && !isset( $_POST['option_page'] ) ) { // This is for back compat and will eventually be removed.
     153        $unregistered = true;
     154        check_admin_referer( 'update-options' );
     155    } else {
     156        $unregistered = false;
     157        check_admin_referer( $option_page . '-options' );
     158    }
     159
     160    if ( !isset( $whitelist_options[ $option_page ] ) )
     161        wp_die( __( '<strong>ERROR</strong>: options page not found.' ) );
     162
     163    if ( 'options' == $option_page ) {
     164        if ( is_multisite() && ! current_user_can( 'manage_network_options' ) ) {
     165            wp_die( __( 'Sorry, you are not allowed to modify unregistered settings for this site.' ) );
     166        }
     167        $options = explode( ',', wp_unslash( $_POST[ 'page_options' ] ) );
     168    } else {
     169        $options = $whitelist_options[ $option_page ];
     170    }
     171
     172    if ( 'general' == $option_page ) {
     173        // Handle custom date/time formats.
     174        if ( !empty($_POST['date_format']) && isset($_POST['date_format_custom']) && '\c\u\s\t\o\m' == wp_unslash( $_POST['date_format'] ) )
     175            $_POST['date_format'] = $_POST['date_format_custom'];
     176        if ( !empty($_POST['time_format']) && isset($_POST['time_format_custom']) && '\c\u\s\t\o\m' == wp_unslash( $_POST['time_format'] ) )
     177            $_POST['time_format'] = $_POST['time_format_custom'];
     178        // Map UTC+- timezones to gmt_offsets and set timezone_string to empty.
     179        if ( !empty($_POST['timezone_string']) && preg_match('/^UTC[+-]/', $_POST['timezone_string']) ) {
     180            $_POST['gmt_offset'] = $_POST['timezone_string'];
     181            $_POST['gmt_offset'] = preg_replace('/UTC\+?/', '', $_POST['gmt_offset']);
     182            $_POST['timezone_string'] = '';
     183        }
     184
     185        // Handle translation install.
     186        if ( ! empty( $_POST['WPLANG'] ) && ( ! is_multisite() || is_super_admin() ) ) { // @todo: Skip if already installed
     187            require_once( ABSPATH . 'wp-admin/includes/translation-install.php' );
     188
     189            if ( wp_can_install_language_pack() ) {
     190                $language = wp_download_language_pack( $_POST['WPLANG'] );
     191                if ( $language ) {
     192                    $_POST['WPLANG'] = $language;
     193                }
     194            }
     195        }
     196    }
     197
     198    if ( $options ) {
     199        $user_language_old = get_user_locale();
     200
     201        foreach ( $options as $option ) {
     202            if ( $unregistered ) {
     203                _deprecated_argument( 'options.php', '2.7.0',
     204                    sprintf(
     205                        /* translators: %s: the option/setting */
     206                        __( 'The %s setting is unregistered. Unregistered settings are deprecated. See https://codex.wordpress.org/Settings_API' ),
     207                        '<code>' . $option . '</code>'
     208                    )
     209                );
     210            }
     211
     212            $option = trim( $option );
     213            $value = null;
     214            if ( isset( $_POST[ $option ] ) ) {
     215                $value = $_POST[ $option ];
     216                if ( ! is_array( $value ) ) {
     217                    $value = trim( $value );
     218                }
     219                $value = wp_unslash( $value );
     220            }
     221            update_option( $option, $value );
     222        }
     223
     224        /*
     225        * Switch translation in case WPLANG was changed.
     226        * The global $locale is used in get_locale() which is
     227        * used as a fallback in get_user_locale().
     228        */
     229        unset( $GLOBALS['locale'] );
     230        $user_language_new = get_user_locale();
     231        if ( $user_language_old !== $user_language_new  ) {
     232            load_default_textdomain( $user_language_new );
     233        }
     234    }
     235
     236    /**
     237    * Handle settings errors and return to options page
     238    */
     239    // If no settings errors were registered add a general 'updated' message.
     240    if ( !count( get_settings_errors() ) )
     241        add_settings_error('general', 'settings_updated', __('Settings saved.'), 'updated');
     242    set_transient('settings_errors', get_settings_errors(), 30);
     243
     244    /**
     245    * Redirect back to the settings page that was submitted
     246    */
     247    $goback = add_query_arg( 'settings-updated', 'true',  wp_get_referer() );
     248    wp_redirect( $goback );
     249    exit;
    249250}
    250251
    251252include( ABSPATH . 'wp-admin/admin-header.php' ); ?>
    include( ABSPATH . 'wp-admin/admin-header.php' ); ?> 
    261262$options = $wpdb->get_results( "SELECT * FROM $wpdb->options ORDER BY option_name" );
    262263
    263264foreach ( (array) $options as $option ) :
    264         $disabled = false;
    265         if ( $option->option_name == '' )
    266                 continue;
    267         if ( is_serialized( $option->option_value ) ) {
    268                 if ( is_serialized_string( $option->option_value ) ) {
    269                         // This is a serialized string, so we should display it.
    270                         $value = maybe_unserialize( $option->option_value );
    271                         $options_to_update[] = $option->option_name;
    272                         $class = 'all-options';
    273                 } else {
    274                         $value = 'SERIALIZED DATA';
    275                         $disabled = true;
    276                         $class = 'all-options disabled';
    277                 }
    278         } else {
    279                 $value = $option->option_value;
    280                 $options_to_update[] = $option->option_name;
    281                 $class = 'all-options';
    282         }
    283         $name = esc_attr( $option->option_name );
    284         ?>
     265    $disabled = false;
     266    if ( $option->option_name == '' )
     267        continue;
     268    if ( is_serialized( $option->option_value ) ) {
     269        if ( is_serialized_string( $option->option_value ) ) {
     270            // This is a serialized string, so we should display it.
     271            $value = maybe_unserialize( $option->option_value );
     272            $options_to_update[] = $option->option_name;
     273            $class = 'all-options';
     274        } else {
     275            $value = 'SERIALIZED DATA';
     276            $disabled = true;
     277            $class = 'all-options disabled';
     278        }
     279    } else {
     280        $value = $option->option_value;
     281        $options_to_update[] = $option->option_name;
     282        $class = 'all-options';
     283    }
     284    $name = esc_attr( $option->option_name );
     285    ?>
    285286<tr>
    286         <th scope="row"><label for="<?php echo $name ?>"><?php echo esc_html( $option->option_name ); ?></label></th>
     287    <th scope="row"><label for="<?php echo $name ?>"><?php echo esc_html( $option->option_name ); ?></label></th>
    287288<td>
    288289<?php if ( strpos( $value, "\n" ) !== false ) : ?>
    289         <textarea class="<?php echo $class ?>" name="<?php echo $name ?>" id="<?php echo $name ?>" cols="30" rows="5"><?php
    290                 echo esc_textarea( $value );
    291         ?></textarea>
    292         <?php else: ?>
    293                 <input class="regular-text <?php echo $class ?>" type="text" name="<?php echo $name ?>" id="<?php echo $name ?>" value="<?php echo esc_attr( $value ) ?>"<?php disabled( $disabled, true ) ?> />
    294         <?php endif ?></td>
     290    <textarea class="<?php echo $class ?>" name="<?php echo $name ?>" id="<?php echo $name ?>" cols="30" rows="5"><?php
     291        echo esc_textarea( $value );
     292    ?></textarea>
     293    <?php else: ?>
     294        <input class="regular-text <?php echo $class ?>" type="text" name="<?php echo $name ?>" id="<?php echo $name ?>" value="<?php echo esc_attr( $value ) ?>"<?php disabled( $disabled, true ) ?> />
     295    <?php endif ?></td>
    295296</tr>
    296297<?php endforeach; ?>
    297298  </table>
  • src/wp-admin/post.php

    diff --git a/src/wp-admin/post.php b/src/wp-admin/post.php
    index cf2bee5790..73d4f7a2fc 100644
    a b require_once( dirname( __FILE__ ) . '/admin.php' ); 
    1414$parent_file = 'edit.php';
    1515$submenu_file = 'edit.php';
    1616
    17 wp_reset_vars( array( 'action' ) );
     17$action = wp_assign_request_var('action');
    1818
    1919if ( isset( $_GET['post'] ) )
    20         $post_id = $post_ID = (int) $_GET['post'];
     20     $post_id = $post_ID = (int) $_GET['post'];
    2121elseif ( isset( $_POST['post_ID'] ) )
    22         $post_id = $post_ID = (int) $_POST['post_ID'];
     22     $post_id = $post_ID = (int) $_POST['post_ID'];
    2323else
    24         $post_id = $post_ID = 0;
     24     $post_id = $post_ID = 0;
    2525
    2626/**
    2727 * @global string  $post_type
    else 
    3131global $post_type, $post_type_object, $post;
    3232
    3333if ( $post_id )
    34         $post = get_post( $post_id );
     34    $post = get_post( $post_id );
    3535
    3636if ( $post ) {
    37         $post_type = $post->post_type;
    38         $post_type_object = get_post_type_object( $post_type );
     37    $post_type = $post->post_type;
     38    $post_type_object = get_post_type_object( $post_type );
    3939}
    4040
    4141if ( isset( $_POST['deletepost'] ) )
    42         $action = 'delete';
     42    $action = 'delete';
    4343elseif ( isset($_POST['wp-preview']) && 'dopreview' == $_POST['wp-preview'] )
    44         $action = 'preview';
     44    $action = 'preview';
    4545
    4646$sendback = wp_get_referer();
    4747if ( ! $sendback ||
    4848     strpos( $sendback, 'post.php' ) !== false ||
    4949     strpos( $sendback, 'post-new.php' ) !== false ) {
    50         if ( 'attachment' == $post_type ) {
    51                 $sendback = admin_url( 'upload.php' );
    52         } else {
    53                 $sendback = admin_url( 'edit.php' );
    54                 if ( ! empty( $post_type ) ) {
    55                         $sendback = add_query_arg( 'post_type', $post_type, $sendback );
    56                 }
    57         }
     50    if ( 'attachment' == $post_type ) {
     51        $sendback = admin_url( 'upload.php' );
     52    } else {
     53        $sendback = admin_url( 'edit.php' );
     54        if ( ! empty( $post_type ) ) {
     55            $sendback = add_query_arg( 'post_type', $post_type, $sendback );
     56        }
     57    }
    5858} else {
    59         $sendback = remove_query_arg( array('trashed', 'untrashed', 'deleted', 'ids'), $sendback );
     59    $sendback = remove_query_arg( array('trashed', 'untrashed', 'deleted', 'ids'), $sendback );
    6060}
    6161
    6262switch($action) {
    6363case 'post-quickdraft-save':
    64         // Check nonce and capabilities
    65         $nonce = $_REQUEST['_wpnonce'];
    66         $error_msg = false;
     64    // Check nonce and capabilities
     65    $nonce = $_REQUEST['_wpnonce'];
     66    $error_msg = false;
    6767
    68         // For output of the quickdraft dashboard widget
    69         require_once ABSPATH . 'wp-admin/includes/dashboard.php';
     68    // For output of the quickdraft dashboard widget
     69    require_once ABSPATH . 'wp-admin/includes/dashboard.php';
    7070
    71         if ( ! wp_verify_nonce( $nonce, 'add-post' ) )
    72                 $error_msg = __( 'Unable to submit this form, please refresh and try again.' );
     71    if ( ! wp_verify_nonce( $nonce, 'add-post' ) )
     72        $error_msg = __( 'Unable to submit this form, please refresh and try again.' );
    7373
    74         if ( ! current_user_can( get_post_type_object( 'post' )->cap->create_posts ) ) {
    75                 exit;
    76         }
     74    if ( ! current_user_can( get_post_type_object( 'post' )->cap->create_posts ) ) {
     75        exit;
     76    }
    7777
    78         if ( $error_msg )
    79                 return wp_dashboard_quick_press( $error_msg );
     78    if ( $error_msg )
     79        return wp_dashboard_quick_press( $error_msg );
    8080
    81         $post = get_post( $_REQUEST['post_ID'] );
    82         check_admin_referer( 'add-' . $post->post_type );
     81    $post = get_post( $_REQUEST['post_ID'] );
     82    check_admin_referer( 'add-' . $post->post_type );
    8383
    84         $_POST['comment_status'] = get_default_comment_status( $post->post_type );
    85         $_POST['ping_status']    = get_default_comment_status( $post->post_type, 'pingback' );
     84    $_POST['comment_status'] = get_default_comment_status( $post->post_type );
     85    $_POST['ping_status']    = get_default_comment_status( $post->post_type, 'pingback' );
    8686
    87         edit_post();
    88         wp_dashboard_quick_press();
    89         exit;
     87    edit_post();
     88    wp_dashboard_quick_press();
     89    exit;
    9090
    9191case 'postajaxpost':
    9292case 'post':
    93         check_admin_referer( 'add-' . $post_type );
    94         $post_id = 'postajaxpost' == $action ? edit_post() : write_post();
    95         redirect_post( $post_id );
    96         exit();
     93    check_admin_referer( 'add-' . $post_type );
     94    $post_id = 'postajaxpost' == $action ? edit_post() : write_post();
     95    redirect_post( $post_id );
     96    exit();
    9797
    9898case 'edit':
    99         $editing = true;
    100 
    101         if ( empty( $post_id ) ) {
    102                 wp_redirect( admin_url('post.php') );
    103                 exit();
    104         }
    105 
    106         if ( ! $post )
    107                 wp_die( __( 'You attempted to edit an item that doesn&#8217;t exist. Perhaps it was deleted?' ) );
    108 
    109         if ( ! $post_type_object )
    110                 wp_die( __( 'Invalid post type.' ) );
    111 
    112         if ( ! in_array( $typenow, get_post_types( array( 'show_ui' => true ) ) ) ) {
    113                 wp_die( __( 'Sorry, you are not allowed to edit posts in this post type.' ) );
    114         }
    115 
    116         if ( ! current_user_can( 'edit_post', $post_id ) )
    117                 wp_die( __( 'Sorry, you are not allowed to edit this item.' ) );
    118 
    119         if ( 'trash' == $post->post_status )
    120                 wp_die( __( 'You can&#8217;t edit this item because it is in the Trash. Please restore it and try again.' ) );
    121 
    122         if ( ! empty( $_GET['get-post-lock'] ) ) {
    123                 check_admin_referer( 'lock-post_' . $post_id );
    124                 wp_set_post_lock( $post_id );
    125                 wp_redirect( get_edit_post_link( $post_id, 'url' ) );
    126                 exit();
    127         }
    128 
    129         $post_type = $post->post_type;
    130         if ( 'post' == $post_type ) {
    131                 $parent_file = "edit.php";
    132                 $submenu_file = "edit.php";
    133                 $post_new_file = "post-new.php";
    134         } elseif ( 'attachment' == $post_type ) {
    135                 $parent_file = 'upload.php';
    136                 $submenu_file = 'upload.php';
    137                 $post_new_file = 'media-new.php';
    138         } else {
    139                 if ( isset( $post_type_object ) && $post_type_object->show_in_menu && $post_type_object->show_in_menu !== true )
    140                         $parent_file = $post_type_object->show_in_menu;
    141                 else
    142                         $parent_file = "edit.php?post_type=$post_type";
    143                 $submenu_file = "edit.php?post_type=$post_type";
    144                 $post_new_file = "post-new.php?post_type=$post_type";
    145         }
    146 
    147         if ( ! wp_check_post_lock( $post->ID ) ) {
    148                 $active_post_lock = wp_set_post_lock( $post->ID );
    149 
    150                 if ( 'attachment' !== $post_type )
    151                         wp_enqueue_script('autosave');
    152         }
    153 
    154         if ( is_multisite() ) {
    155                 add_action( 'admin_footer', '_admin_notice_post_locked' );
    156         } else {
    157                 $check_users = get_users( array( 'fields' => 'ID', 'number' => 2 ) );
    158 
    159                 if ( count( $check_users ) > 1 )
    160                         add_action( 'admin_footer', '_admin_notice_post_locked' );
    161 
    162                 unset( $check_users );
    163         }
    164 
    165         $title = $post_type_object->labels->edit_item;
    166         $post = get_post($post_id, OBJECT, 'edit');
    167 
    168         if ( post_type_supports($post_type, 'comments') ) {
    169                 wp_enqueue_script('admin-comments');
    170                 enqueue_comment_hotkeys_js();
    171         }
    172 
    173         include( ABSPATH . 'wp-admin/edit-form-advanced.php' );
    174 
    175         break;
     99    $editing = true;
     100
     101    if ( empty( $post_id ) ) {
     102        wp_redirect( admin_url('post.php') );
     103        exit();
     104    }
     105
     106    if ( ! $post )
     107        wp_die( __( 'You attempted to edit an item that doesn&#8217;t exist. Perhaps it was deleted?' ) );
     108
     109    if ( ! $post_type_object )
     110        wp_die( __( 'Invalid post type.' ) );
     111
     112    if ( ! in_array( $typenow, get_post_types( array( 'show_ui' => true ) ) ) ) {
     113        wp_die( __( 'Sorry, you are not allowed to edit posts in this post type.' ) );
     114    }
     115
     116    if ( ! current_user_can( 'edit_post', $post_id ) )
     117        wp_die( __( 'Sorry, you are not allowed to edit this item.' ) );
     118
     119    if ( 'trash' == $post->post_status )
     120        wp_die( __( 'You can&#8217;t edit this item because it is in the Trash. Please restore it and try again.' ) );
     121
     122    if ( ! empty( $_GET['get-post-lock'] ) ) {
     123        check_admin_referer( 'lock-post_' . $post_id );
     124        wp_set_post_lock( $post_id );
     125        wp_redirect( get_edit_post_link( $post_id, 'url' ) );
     126        exit();
     127    }
     128
     129    $post_type = $post->post_type;
     130    if ( 'post' == $post_type ) {
     131        $parent_file = "edit.php";
     132        $submenu_file = "edit.php";
     133        $post_new_file = "post-new.php";
     134    } elseif ( 'attachment' == $post_type ) {
     135        $parent_file = 'upload.php';
     136        $submenu_file = 'upload.php';
     137        $post_new_file = 'media-new.php';
     138    } else {
     139        if ( isset( $post_type_object ) && $post_type_object->show_in_menu && $post_type_object->show_in_menu !== true )
     140            $parent_file = $post_type_object->show_in_menu;
     141        else
     142            $parent_file = "edit.php?post_type=$post_type";
     143        $submenu_file = "edit.php?post_type=$post_type";
     144        $post_new_file = "post-new.php?post_type=$post_type";
     145    }
     146
     147    if ( ! wp_check_post_lock( $post->ID ) ) {
     148        $active_post_lock = wp_set_post_lock( $post->ID );
     149
     150        if ( 'attachment' !== $post_type )
     151            wp_enqueue_script('autosave');
     152    }
     153
     154    if ( is_multisite() ) {
     155        add_action( 'admin_footer', '_admin_notice_post_locked' );
     156    } else {
     157        $check_users = get_users( array( 'fields' => 'ID', 'number' => 2 ) );
     158
     159        if ( count( $check_users ) > 1 )
     160            add_action( 'admin_footer', '_admin_notice_post_locked' );
     161
     162        unset( $check_users );
     163    }
     164
     165    $title = $post_type_object->labels->edit_item;
     166    $post = get_post($post_id, OBJECT, 'edit');
     167
     168    if ( post_type_supports($post_type, 'comments') ) {
     169        wp_enqueue_script('admin-comments');
     170        enqueue_comment_hotkeys_js();
     171    }
     172
     173    include( ABSPATH . 'wp-admin/edit-form-advanced.php' );
     174
     175    break;
    176176
    177177case 'editattachment':
    178         check_admin_referer('update-post_' . $post_id);
     178    check_admin_referer('update-post_' . $post_id);
    179179
    180         // Don't let these be changed
    181         unset($_POST['guid']);
    182         $_POST['post_type'] = 'attachment';
     180    // Don't let these be changed
     181    unset($_POST['guid']);
     182    $_POST['post_type'] = 'attachment';
    183183
    184         // Update the thumbnail filename
    185         $newmeta = wp_get_attachment_metadata( $post_id, true );
    186         $newmeta['thumb'] = $_POST['thumb'];
     184    // Update the thumbnail filename
     185    $newmeta = wp_get_attachment_metadata( $post_id, true );
     186    $newmeta['thumb'] = $_POST['thumb'];
    187187
    188         wp_update_attachment_metadata( $post_id, $newmeta );
     188    wp_update_attachment_metadata( $post_id, $newmeta );
    189189
    190190case 'editpost':
    191         check_admin_referer('update-post_' . $post_id);
     191    check_admin_referer('update-post_' . $post_id);
    192192
    193         $post_id = edit_post();
     193    $post_id = edit_post();
    194194
    195         // Session cookie flag that the post was saved
    196         if ( isset( $_COOKIE['wp-saving-post'] ) && $_COOKIE['wp-saving-post'] === $post_id . '-check' ) {
    197                 setcookie( 'wp-saving-post', $post_id . '-saved', time() + DAY_IN_SECONDS, ADMIN_COOKIE_PATH, COOKIE_DOMAIN, is_ssl() );
    198         }
     195    // Session cookie flag that the post was saved
     196    if ( isset( $_COOKIE['wp-saving-post'] ) && $_COOKIE['wp-saving-post'] === $post_id . '-check' ) {
     197        setcookie( 'wp-saving-post', $post_id . '-saved', time() + DAY_IN_SECONDS, ADMIN_COOKIE_PATH, COOKIE_DOMAIN, is_ssl() );
     198    }
    199199
    200         redirect_post($post_id); // Send user on their way while we keep working
     200    redirect_post($post_id); // Send user on their way while we keep working
    201201
    202         exit();
     202    exit();
    203203
    204204case 'trash':
    205         check_admin_referer('trash-post_' . $post_id);
     205    check_admin_referer('trash-post_' . $post_id);
    206206
    207         if ( ! $post )
    208                 wp_die( __( 'The item you are trying to move to the Trash no longer exists.' ) );
     207    if ( ! $post )
     208        wp_die( __( 'The item you are trying to move to the Trash no longer exists.' ) );
    209209
    210         if ( ! $post_type_object )
    211                 wp_die( __( 'Invalid post type.' ) );
     210    if ( ! $post_type_object )
     211        wp_die( __( 'Invalid post type.' ) );
    212212
    213         if ( ! current_user_can( 'delete_post', $post_id ) )
    214                 wp_die( __( 'Sorry, you are not allowed to move this item to the Trash.' ) );
     213    if ( ! current_user_can( 'delete_post', $post_id ) )
     214        wp_die( __( 'Sorry, you are not allowed to move this item to the Trash.' ) );
    215215
    216         if ( $user_id = wp_check_post_lock( $post_id ) ) {
    217                 $user = get_userdata( $user_id );
    218                 wp_die( sprintf( __( 'You cannot move this item to the Trash. %s is currently editing.' ), $user->display_name ) );
    219         }
     216    if ( $user_id = wp_check_post_lock( $post_id ) ) {
     217        $user = get_userdata( $user_id );
     218        wp_die( sprintf( __( 'You cannot move this item to the Trash. %s is currently editing.' ), $user->display_name ) );
     219    }
    220220
    221         if ( ! wp_trash_post( $post_id ) )
    222                 wp_die( __( 'Error in moving to Trash.' ) );
     221    if ( ! wp_trash_post( $post_id ) )
     222        wp_die( __( 'Error in moving to Trash.' ) );
    223223
    224         wp_redirect( add_query_arg( array('trashed' => 1, 'ids' => $post_id), $sendback ) );
    225         exit();
     224    wp_redirect( add_query_arg( array('trashed' => 1, 'ids' => $post_id), $sendback ) );
     225    exit();
    226226
    227227case 'untrash':
    228         check_admin_referer('untrash-post_' . $post_id);
     228    check_admin_referer('untrash-post_' . $post_id);
    229229
    230         if ( ! $post )
    231                 wp_die( __( 'The item you are trying to restore from the Trash no longer exists.' ) );
     230    if ( ! $post )
     231        wp_die( __( 'The item you are trying to restore from the Trash no longer exists.' ) );
    232232
    233         if ( ! $post_type_object )
    234                 wp_die( __( 'Invalid post type.' ) );
     233    if ( ! $post_type_object )
     234        wp_die( __( 'Invalid post type.' ) );
    235235
    236         if ( ! current_user_can( 'delete_post', $post_id ) )
    237                 wp_die( __( 'Sorry, you are not allowed to restore this item from the Trash.' ) );
     236    if ( ! current_user_can( 'delete_post', $post_id ) )
     237        wp_die( __( 'Sorry, you are not allowed to restore this item from the Trash.' ) );
    238238
    239         if ( ! wp_untrash_post( $post_id ) )
    240                 wp_die( __( 'Error in restoring from Trash.' ) );
     239    if ( ! wp_untrash_post( $post_id ) )
     240        wp_die( __( 'Error in restoring from Trash.' ) );
    241241
    242         wp_redirect( add_query_arg('untrashed', 1, $sendback) );
    243         exit();
     242    wp_redirect( add_query_arg('untrashed', 1, $sendback) );
     243    exit();
    244244
    245245case 'delete':
    246         check_admin_referer('delete-post_' . $post_id);
     246    check_admin_referer('delete-post_' . $post_id);
    247247
    248         if ( ! $post )
    249                 wp_die( __( 'This item has already been deleted.' ) );
     248    if ( ! $post )
     249        wp_die( __( 'This item has already been deleted.' ) );
    250250
    251         if ( ! $post_type_object )
    252                 wp_die( __( 'Invalid post type.' ) );
     251    if ( ! $post_type_object )
     252        wp_die( __( 'Invalid post type.' ) );
    253253
    254         if ( ! current_user_can( 'delete_post', $post_id ) )
    255                 wp_die( __( 'Sorry, you are not allowed to delete this item.' ) );
     254    if ( ! current_user_can( 'delete_post', $post_id ) )
     255        wp_die( __( 'Sorry, you are not allowed to delete this item.' ) );
    256256
    257         if ( $post->post_type == 'attachment' ) {
    258                 $force = ( ! MEDIA_TRASH );
    259                 if ( ! wp_delete_attachment( $post_id, $force ) )
    260                         wp_die( __( 'Error in deleting.' ) );
    261         } else {
    262                 if ( ! wp_delete_post( $post_id, true ) )
    263                         wp_die( __( 'Error in deleting.' ) );
    264         }
     257    if ( $post->post_type == 'attachment' ) {
     258        $force = ( ! MEDIA_TRASH );
     259        if ( ! wp_delete_attachment( $post_id, $force ) )
     260            wp_die( __( 'Error in deleting.' ) );
     261    } else {
     262        if ( ! wp_delete_post( $post_id, true ) )
     263            wp_die( __( 'Error in deleting.' ) );
     264    }
    265265
    266         wp_redirect( add_query_arg('deleted', 1, $sendback) );
    267         exit();
     266    wp_redirect( add_query_arg('deleted', 1, $sendback) );
     267    exit();
    268268
    269269case 'preview':
    270         check_admin_referer( 'update-post_' . $post_id );
     270    check_admin_referer( 'update-post_' . $post_id );
    271271
    272         $url = post_preview();
     272    $url = post_preview();
    273273
    274         wp_redirect($url);
    275         exit();
     274    wp_redirect($url);
     275    exit();
    276276
    277277default:
    278         /**
    279         * Fires for a given custom post action request.
    280         *
    281         * The dynamic portion of the hook name, `$action`, refers to the custom post action.
    282         *
    283         * @since 4.6.0
    284         *
    285         * @param int $post_id Post ID sent with the request.
    286         */
    287         do_action( "post_action_{$action}", $post_id );
    288 
    289         wp_redirect( admin_url('edit.php') );
    290         exit();
     278    /**
     279    * Fires for a given custom post action request.
     280    *
     281    * The dynamic portion of the hook name, `$action`, refers to the custom post action.
     282    *
     283    * @since 4.6.0
     284    *
     285    * @param int $post_id Post ID sent with the request.
     286    */
     287    do_action( "post_action_{$action}", $post_id );
     288
     289    wp_redirect( admin_url('edit.php') );
     290    exit();
    291291} // end switch
    292292include( ABSPATH . 'wp-admin/admin-footer.php' );
  • src/wp-admin/revision.php

    diff --git a/src/wp-admin/revision.php b/src/wp-admin/revision.php
    index c86f78a451..fae38191a1 100644
    a b require_once( dirname( __FILE__ ) . '/admin.php' ); 
    2020
    2121require ABSPATH . 'wp-admin/includes/revision.php';
    2222
    23 wp_reset_vars( array( 'revision', 'action', 'from', 'to' ) );
     23$revision = wp_assign_request_var('revision');
     24$action = wp_assign_request_var('action');
     25$from = wp_assign_request_var('from');
     26$to = wp_assign_request_var('to');
    2427
    2528$revision_id = absint( $revision );
    2629
    2730$from = is_numeric( $from ) ? absint( $from ) : null;
    2831if ( ! $revision_id )
    29         $revision_id = absint( $to );
     32    $revision_id = absint( $to );
    3033$redirect = 'edit.php';
    3134
    3235switch ( $action ) {
    3336case 'restore' :
    34         if ( ! $revision = wp_get_post_revision( $revision_id ) )
    35                 break;
     37    if ( ! $revision = wp_get_post_revision( $revision_id ) )
     38        break;
    3639
    37         if ( ! current_user_can( 'edit_post', $revision->post_parent ) )
    38                 break;
     40    if ( ! current_user_can( 'edit_post', $revision->post_parent ) )
     41        break;
    3942
    40         if ( ! $post = get_post( $revision->post_parent ) )
    41                 break;
     43    if ( ! $post = get_post( $revision->post_parent ) )
     44        break;
    4245
    43         // Restore if revisions are enabled or this is an autosave.
    44         if ( ! wp_revisions_enabled( $post ) && ! wp_is_post_autosave( $revision ) ) {
    45                 $redirect = 'edit.php?post_type=' . $post->post_type;
    46                 break;
    47         }
     46    // Restore if revisions are enabled or this is an autosave.
     47    if ( ! wp_revisions_enabled( $post ) && ! wp_is_post_autosave( $revision ) ) {
     48        $redirect = 'edit.php?post_type=' . $post->post_type;
     49        break;
     50    }
    4851
    49         // Don't allow revision restore when post is locked
    50         if ( wp_check_post_lock( $post->ID ) )
    51                 break;
     52    // Don't allow revision restore when post is locked
     53    if ( wp_check_post_lock( $post->ID ) )
     54        break;
    5255
    53         check_admin_referer( "restore-post_{$revision->ID}" );
     56    check_admin_referer( "restore-post_{$revision->ID}" );
    5457
    55         wp_restore_post_revision( $revision->ID );
    56         $redirect = add_query_arg( array( 'message' => 5, 'revision' => $revision->ID ), get_edit_post_link( $post->ID, 'url' ) );
    57         break;
     58    wp_restore_post_revision( $revision->ID );
     59    $redirect = add_query_arg( array( 'message' => 5, 'revision' => $revision->ID ), get_edit_post_link( $post->ID, 'url' ) );
     60    break;
    5861case 'view' :
    5962case 'edit' :
    6063default :
    61         if ( ! $revision = wp_get_post_revision( $revision_id ) )
    62                 break;
    63         if ( ! $post = get_post( $revision->post_parent ) )
    64                 break;
    65 
    66         if ( ! current_user_can( 'read_post', $revision->ID ) || ! current_user_can( 'edit_post', $revision->post_parent ) )
    67                 break;
    68 
    69         // Revisions disabled and we're not looking at an autosave
    70         if ( ! wp_revisions_enabled( $post ) && ! wp_is_post_autosave( $revision ) ) {
    71                 $redirect = 'edit.php?post_type=' . $post->post_type;
    72                 break;
    73         }
    74 
    75         $post_edit_link = get_edit_post_link();
    76         $post_title     = '<a href="' . $post_edit_link . '">' . _draft_or_post_title() . '</a>';
    77         /* translators: 1: Post title */
    78         $h1             = sprintf( __( 'Compare Revisions of &#8220;%1$s&#8221;' ), $post_title );
    79         $return_to_post = '<a href="' . $post_edit_link . '">' . __( '&larr; Return to editor' ) . '</a>';
    80         $title          = __( 'Revisions' );
    81 
    82         $redirect = false;
    83         break;
     64    if ( ! $revision = wp_get_post_revision( $revision_id ) )
     65        break;
     66    if ( ! $post = get_post( $revision->post_parent ) )
     67        break;
     68
     69    if ( ! current_user_can( 'read_post', $revision->ID ) || ! current_user_can( 'edit_post', $revision->post_parent ) )
     70        break;
     71
     72    // Revisions disabled and we're not looking at an autosave
     73    if ( ! wp_revisions_enabled( $post ) && ! wp_is_post_autosave( $revision ) ) {
     74        $redirect = 'edit.php?post_type=' . $post->post_type;
     75        break;
     76    }
     77
     78    $post_edit_link = get_edit_post_link();
     79    $post_title     = '<a href="' . $post_edit_link . '">' . _draft_or_post_title() . '</a>';
     80    /* translators: 1: Post title */
     81    $h1             = sprintf( __( 'Compare Revisions of &#8220;%1$s&#8221;' ), $post_title );
     82    $return_to_post = '<a href="' . $post_edit_link . '">' . __( '&larr; Return to editor' ) . '</a>';
     83    $title          = __( 'Revisions' );
     84
     85    $redirect = false;
     86    break;
    8487}
    8588
    8689// Empty post_type means either malformed object found, or no valid parent was found.
    8790if ( ! $redirect && empty( $post->post_type ) )
    88         $redirect = 'edit.php';
     91    $redirect = 'edit.php';
    8992
    9093if ( ! empty( $redirect ) ) {
    91         wp_redirect( $redirect );
    92         exit;
     94    wp_redirect( $redirect );
     95    exit;
    9396}
    9497
    9598// This is so that the correct "Edit" menu item is selected.
    9699if ( ! empty( $post->post_type ) && 'post' != $post->post_type )
    97         $parent_file = $submenu_file = 'edit.php?post_type=' . $post->post_type;
     100    $parent_file = $submenu_file = 'edit.php?post_type=' . $post->post_type;
    98101else
    99         $parent_file = $submenu_file = 'edit.php';
     102    $parent_file = $submenu_file = 'edit.php';
    100103
    101104wp_enqueue_script( 'revisions' );
    102105wp_localize_script( 'revisions', '_wpRevisionsSettings', wp_prepare_revisions_for_js( $post, $revision_id, $from ) );
    $revisions_overview .= '<li>' . __( 'Compare two different revisions by <strong> 
    111114$revisions_overview .= '<li>' . __( 'To restore a revision, <strong>click Restore This Revision</strong>.' ) . '</li></ul>';
    112115
    113116get_current_screen()->add_help_tab( array(
    114         'id'      => 'revisions-overview',
    115         'title'   => __( 'Overview' ),
    116         'content' => $revisions_overview
     117    'id'      => 'revisions-overview',
     118    'title'   => __( 'Overview' ),
     119    'content' => $revisions_overview
    117120) );
    118121
    119122$revisions_sidebar  = '<p><strong>' . __( 'For more information:' ) . '</strong></p>';
    require_once( ABSPATH . 'wp-admin/admin-header.php' ); 
    127130?>
    128131
    129132<div class="wrap">
    130         <h1 class="long-header"><?php echo $h1; ?></h1>
    131         <?php echo $return_to_post; ?>
     133    <h1 class="long-header"><?php echo $h1; ?></h1>
     134    <?php echo $return_to_post; ?>
    132135</div>
    133136<?php
    134137wp_print_revision_templates();
  • src/wp-admin/theme-editor.php

    diff --git a/src/wp-admin/theme-editor.php b/src/wp-admin/theme-editor.php
    index 03b91944ea..3c1e50ffe6 100644
    a b  
    1010require_once( dirname( __FILE__ ) . '/admin.php' );
    1111
    1212if ( is_multisite() && ! is_network_admin() ) {
    13         wp_redirect( network_admin_url( 'theme-editor.php' ) );
    14         exit();
     13    wp_redirect( network_admin_url( 'theme-editor.php' ) );
     14    exit();
    1515}
    1616
    1717if ( !current_user_can('edit_themes') )
    18         wp_die('<p>'.__('Sorry, you are not allowed to edit templates for this site.').'</p>');
     18    wp_die('<p>'.__('Sorry, you are not allowed to edit templates for this site.').'</p>');
    1919
    2020$title = __("Edit Themes");
    2121$parent_file = 'themes.php';
    get_current_screen()->add_help_tab( array( 
    2424'id'            => 'overview',
    2525'title'         => __('Overview'),
    2626'content'       =>
    27         '<p>' . __('You can use the Theme Editor to edit the individual CSS and PHP files which make up your theme.') . '</p>
    28         <p>' . __( 'Begin by choosing a theme to edit from the dropdown menu and clicking the Select button. A list then appears of the theme&#8217;s template files. Clicking once on any file name causes the file to appear in the large Editor box.' ) . '</p>
    29         <p>' . __('For PHP files, you can use the Documentation dropdown to select from functions recognized in that file. Look Up takes you to a web page with reference material about that particular function.') . '</p>
    30         <p id="newcontent-description">' . __( 'In the editing area the Tab key enters a tab character. To move below this area by pressing Tab, press the Esc key followed by the Tab key. In some cases the Esc key will need to be pressed twice before the Tab key will allow you to continue.' ) . '</p>
    31         <p>' . __('After typing in your edits, click Update File.') . '</p>
    32         <p>' . __('<strong>Advice:</strong> think very carefully about your site crashing if you are live-editing the theme currently in use.') . '</p>
    33         <p>' . sprintf( __('Upgrading to a newer version of the same theme will override changes made here. To avoid this, consider creating a <a href="%s">child theme</a> instead.'), __('https://codex.wordpress.org/Child_Themes') ) . '</p>' .
    34         ( is_network_admin() ? '<p>' . __('Any edits to files from this screen will be reflected on all sites in the network.') . '</p>' : '' )
     27    '<p>' . __('You can use the Theme Editor to edit the individual CSS and PHP files which make up your theme.') . '</p>
     28    <p>' . __( 'Begin by choosing a theme to edit from the dropdown menu and clicking the Select button. A list then appears of the theme&#8217;s template files. Clicking once on any file name causes the file to appear in the large Editor box.' ) . '</p>
     29    <p>' . __('For PHP files, you can use the Documentation dropdown to select from functions recognized in that file. Look Up takes you to a web page with reference material about that particular function.') . '</p>
     30    <p id="newcontent-description">' . __( 'In the editing area the Tab key enters a tab character. To move below this area by pressing Tab, press the Esc key followed by the Tab key. In some cases the Esc key will need to be pressed twice before the Tab key will allow you to continue.' ) . '</p>
     31    <p>' . __('After typing in your edits, click Update File.') . '</p>
     32    <p>' . __('<strong>Advice:</strong> think very carefully about your site crashing if you are live-editing the theme currently in use.') . '</p>
     33    <p>' . sprintf( __('Upgrading to a newer version of the same theme will override changes made here. To avoid this, consider creating a <a href="%s">child theme</a> instead.'), __('https://codex.wordpress.org/Child_Themes') ) . '</p>' .
     34    ( is_network_admin() ? '<p>' . __('Any edits to files from this screen will be reflected on all sites in the network.') . '</p>' : '' )
    3535) );
    3636
    3737get_current_screen()->set_help_sidebar(
    38         '<p><strong>' . __('For more information:') . '</strong></p>' .
    39         '<p>' . __('<a href="https://codex.wordpress.org/Theme_Development">Documentation on Theme Development</a>') . '</p>' .
    40         '<p>' . __('<a href="https://codex.wordpress.org/Using_Themes">Documentation on Using Themes</a>') . '</p>' .
    41         '<p>' . __('<a href="https://codex.wordpress.org/Editing_Files">Documentation on Editing Files</a>') . '</p>' .
    42         '<p>' . __('<a href="https://codex.wordpress.org/Template_Tags">Documentation on Template Tags</a>') . '</p>' .
    43         '<p>' . __('<a href="https://wordpress.org/support/">Support Forums</a>') . '</p>'
     38    '<p><strong>' . __('For more information:') . '</strong></p>' .
     39    '<p>' . __('<a href="https://codex.wordpress.org/Theme_Development">Documentation on Theme Development</a>') . '</p>' .
     40    '<p>' . __('<a href="https://codex.wordpress.org/Using_Themes">Documentation on Using Themes</a>') . '</p>' .
     41    '<p>' . __('<a href="https://codex.wordpress.org/Editing_Files">Documentation on Editing Files</a>') . '</p>' .
     42    '<p>' . __('<a href="https://codex.wordpress.org/Template_Tags">Documentation on Template Tags</a>') . '</p>' .
     43    '<p>' . __('<a href="https://wordpress.org/support/">Support Forums</a>') . '</p>'
    4444);
    4545
    46 wp_reset_vars( array( 'action', 'error', 'file', 'theme' ) );
     46$action = wp_assign_request_var('action');
     47$error = wp_assign_request_var('error');
     48$file = wp_assign_request_var('file');
     49$theme = wp_assign_request_var('theme');
    4750
    4851if ( $theme ) {
    49         $stylesheet = $theme;
     52    $stylesheet = $theme;
    5053} else {
    51         $stylesheet = get_stylesheet();
     54    $stylesheet = get_stylesheet();
    5255}
    5356
    5457$theme = wp_get_theme( $stylesheet );
    5558
    5659if ( ! $theme->exists() ) {
    57         wp_die( __( 'The requested theme does not exist.' ) );
     60    wp_die( __( 'The requested theme does not exist.' ) );
    5861}
    5962
    6063if ( $theme->errors() && 'theme_no_stylesheet' == $theme->errors()->get_error_code() ) {
    61         wp_die( __( 'The requested theme does not exist.' ) . ' ' . $theme->errors()->get_error_message() );
     64    wp_die( __( 'The requested theme does not exist.' ) . ' ' . $theme->errors()->get_error_message() );
    6265}
    6366
    6467$allowed_files = $style_files = array();
    $file_types = apply_filters( 'wp_theme_editor_filetypes', $default_types, $theme 
    7982$file_types = array_unique( array_merge( $file_types, $default_types ) );
    8083
    8184foreach ( $file_types as $type ) {
    82         switch ( $type ) {
    83                 case 'php':
    84                         $allowed_files += $theme->get_files( 'php', 1 );
    85                         $has_templates = ! empty( $allowed_files );
    86                         break;
    87                 case 'css':
    88                         $style_files = $theme->get_files( 'css' );
    89                         $allowed_files['style.css'] = $style_files['style.css'];
    90                         $allowed_files += $style_files;
    91                         break;
    92                 default:
    93                         $allowed_files += $theme->get_files( $type );
    94                         break;
    95         }
     85    switch ( $type ) {
     86        case 'php':
     87            $allowed_files += $theme->get_files( 'php', 1 );
     88            $has_templates = ! empty( $allowed_files );
     89            break;
     90        case 'css':
     91            $style_files = $theme->get_files( 'css' );
     92            $allowed_files['style.css'] = $style_files['style.css'];
     93            $allowed_files += $style_files;
     94            break;
     95        default:
     96            $allowed_files += $theme->get_files( $type );
     97            break;
     98    }
    9699}
    97100
    98101if ( empty( $file ) ) {
    99         $relative_file = 'style.css';
    100         $file = $allowed_files['style.css'];
     102    $relative_file = 'style.css';
     103    $file = $allowed_files['style.css'];
    101104} else {
    102         $relative_file = $file;
    103         $file = $theme->get_stylesheet_directory() . '/' . $relative_file;
     105    $relative_file = $file;
     106    $file = $theme->get_stylesheet_directory() . '/' . $relative_file;
    104107}
    105108
    106109validate_file_to_edit( $file, $allowed_files );
    $scrollto = isset( $_REQUEST['scrollto'] ) ? (int) $_REQUEST['scrollto'] : 0; 
    108111
    109112switch( $action ) {
    110113case 'update':
    111         check_admin_referer( 'edit-theme_' . $file . $stylesheet );
    112         $newcontent = wp_unslash( $_POST['newcontent'] );
    113         $location = 'theme-editor.php?file=' . urlencode( $relative_file ) . '&theme=' . urlencode( $stylesheet ) . '&scrollto=' . $scrollto;
    114         if ( is_writeable( $file ) ) {
    115                 // is_writable() not always reliable, check return value. see comments @ https://secure.php.net/is_writable
    116                 $f = fopen( $file, 'w+' );
    117                 if ( $f !== false ) {
    118                         fwrite( $f, $newcontent );
    119                         fclose( $f );
    120                         $location .= '&updated=true';
    121                         $theme->cache_delete();
    122                 }
    123         }
    124         wp_redirect( $location );
    125         exit;
     114    check_admin_referer( 'edit-theme_' . $file . $stylesheet );
     115    $newcontent = wp_unslash( $_POST['newcontent'] );
     116    $location = 'theme-editor.php?file=' . urlencode( $relative_file ) . '&theme=' . urlencode( $stylesheet ) . '&scrollto=' . $scrollto;
     117    if ( is_writeable( $file ) ) {
     118        // is_writable() not always reliable, check return value. see comments @ https://secure.php.net/is_writable
     119        $f = fopen( $file, 'w+' );
     120        if ( $f !== false ) {
     121            fwrite( $f, $newcontent );
     122            fclose( $f );
     123            $location .= '&updated=true';
     124            $theme->cache_delete();
     125        }
     126    }
     127    wp_redirect( $location );
     128    exit;
    126129
    127130default:
    128131
    129         require_once( ABSPATH . 'wp-admin/admin-header.php' );
     132    require_once( ABSPATH . 'wp-admin/admin-header.php' );
    130133
    131         update_recently_edited( $file );
     134    update_recently_edited( $file );
    132135
    133         if ( ! is_file( $file ) )
    134                 $error = true;
     136    if ( ! is_file( $file ) )
     137        $error = true;
    135138
    136         $content = '';
    137         if ( ! $error && filesize( $file ) > 0 ) {
    138                 $f = fopen($file, 'r');
    139                 $content = fread($f, filesize($file));
     139    $content = '';
     140    if ( ! $error && filesize( $file ) > 0 ) {
     141        $f = fopen($file, 'r');
     142        $content = fread($f, filesize($file));
    140143
    141                 if ( '.php' == substr( $file, strrpos( $file, '.' ) ) ) {
    142                         $functions = wp_doc_link_parse( $content );
     144        if ( '.php' == substr( $file, strrpos( $file, '.' ) ) ) {
     145            $functions = wp_doc_link_parse( $content );
    143146
    144                         $docs_select = '<select name="docs-list" id="docs-list">';
    145                         $docs_select .= '<option value="">' . esc_attr__( 'Function Name&hellip;' ) . '</option>';
    146                         foreach ( $functions as $function ) {
    147                                 $docs_select .= '<option value="' . esc_attr( urlencode( $function ) ) . '">' . htmlspecialchars( $function ) . '()</option>';
    148                         }
    149                         $docs_select .= '</select>';
    150                 }
     147            $docs_select = '<select name="docs-list" id="docs-list">';
     148            $docs_select .= '<option value="">' . esc_attr__( 'Function Name&hellip;' ) . '</option>';
     149            foreach ( $functions as $function ) {
     150                $docs_select .= '<option value="' . esc_attr( urlencode( $function ) ) . '">' . htmlspecialchars( $function ) . '()</option>';
     151            }
     152            $docs_select .= '</select>';
     153        }
    151154
    152                 $content = esc_textarea( $content );
    153         }
     155        $content = esc_textarea( $content );
     156    }
    154157
    155         if ( isset( $_GET['updated'] ) ) : ?>
     158    if ( isset( $_GET['updated'] ) ) : ?>
    156159 <div id="message" class="updated notice is-dismissible"><p><?php _e( 'File edited successfully.' ) ?></p></div>
    157160<?php endif;
    158161
    159162$description = get_file_description( $relative_file );
    160163$file_show = array_search( $file, array_filter( $allowed_files ) );
    161164if ( $description != $file_show )
    162         $description .= ' <span>(' . $file_show . ')</span>';
     165    $description .= ' <span>(' . $file_show . ')</span>';
    163166?>
    164167<div class="wrap">
    165168<h1><?php echo esc_html( $title ); ?></h1>
    if ( $description != $file_show ) 
    169172<h2><?php echo $theme->display( 'Name' ); if ( $description ) echo ': ' . $description; ?></h2>
    170173</div>
    171174<div class="alignright">
    172         <form action="theme-editor.php" method="post">
    173                 <strong><label for="theme"><?php _e('Select theme to edit:'); ?> </label></strong>
    174                 <select name="theme" id="theme">
     175    <form action="theme-editor.php" method="post">
     176        <strong><label for="theme"><?php _e('Select theme to edit:'); ?> </label></strong>
     177        <select name="theme" id="theme">
    175178<?php
    176179foreach ( wp_get_themes( array( 'errors' => null ) ) as $a_stylesheet => $a_theme ) {
    177         if ( $a_theme->errors() && 'theme_no_stylesheet' == $a_theme->errors()->get_error_code() )
    178                 continue;
     180    if ( $a_theme->errors() && 'theme_no_stylesheet' == $a_theme->errors()->get_error_code() )
     181        continue;
    179182
    180         $selected = $a_stylesheet == $stylesheet ? ' selected="selected"' : '';
    181         echo "\n\t" . '<option value="' . esc_attr( $a_stylesheet ) . '"' . $selected . '>' . $a_theme->display('Name') . '</option>';
     183    $selected = $a_stylesheet == $stylesheet ? ' selected="selected"' : '';
     184    echo "\n\t" . '<option value="' . esc_attr( $a_stylesheet ) . '"' . $selected . '>' . $a_theme->display('Name') . '</option>';
    182185}
    183186?>
    184                 </select>
    185                 <?php submit_button( __( 'Select' ), '', 'Submit', false ); ?>
    186         </form>
     187        </select>
     188        <?php submit_button( __( 'Select' ), '', 'Submit', false ); ?>
     189    </form>
    187190</div>
    188191<br class="clear" />
    189192</div>
    190193<?php
    191194if ( $theme->errors() )
    192         echo '<div class="error"><p><strong>' . __( 'This theme is broken.' ) . '</strong> ' . $theme->errors()->get_error_message() . '</p></div>';
     195    echo '<div class="error"><p><strong>' . __( 'This theme is broken.' ) . '</strong> ' . $theme->errors()->get_error_message() . '</p></div>';
    193196?>
    194         <div id="templateside">
     197    <div id="templateside">
    195198<?php
    196199if ( $allowed_files ) :
    197         $previous_file_type = '';
    198 
    199         foreach ( $allowed_files as $filename => $absolute_filename ) :
    200                 $file_type = substr( $filename, strrpos( $filename, '.' ) );
    201 
    202                 if ( $file_type !== $previous_file_type ) {
    203                         if ( '' !== $previous_file_type ) {
    204                                 echo "\t</ul>\n";
    205                         }
    206 
    207                         switch ( $file_type ) {
    208                                 case '.php':
    209                                         if ( $has_templates || $theme->parent() ) :
    210                                                 echo "\t<h2>" . __( 'Templates' ) . "</h2>\n";
    211                                                 if ( $theme->parent() ) {
    212                                                         echo '<p class="howto">' . sprintf( __( 'This child theme inherits templates from a parent theme, %s.' ),
    213                                                                 sprintf( '<a href="%s">%s</a>',
    214                                                                         self_admin_url( 'theme-editor.php?theme=' . urlencode( $theme->get_template() ) ),
    215                                                                         $theme->parent()->display( 'Name' )
    216                                                                 )
    217                                                         ) . "</p>\n";
    218                                                 }
    219                                         endif;
    220                                         break;
    221                                 case '.css':
    222                                         echo "\t<h2>" . _x( 'Styles', 'Theme stylesheets in theme editor' ) . "</h2>\n";
    223                                         break;
    224                                 default:
    225                                         /* translators: %s: file extension */
    226                                         echo "\t<h2>" . sprintf( __( '%s files' ), $file_type ) . "</h2>\n";
    227                                         break;
    228                         }
    229 
    230                         echo "\t<ul>\n";
    231                 }
    232 
    233                 $file_description = get_file_description( $filename );
    234                 if ( $filename !== basename( $absolute_filename ) || $file_description !== $filename ) {
    235                         $file_description .= '<br /><span class="nonessential">(' . $filename . ')</span>';
    236                 }
    237 
    238                 if ( $absolute_filename === $file ) {
    239                         $file_description = '<span class="highlight">' . $file_description . '</span>';
    240                 }
    241 
    242                 $previous_file_type = $file_type;
     200    $previous_file_type = '';
     201
     202    foreach ( $allowed_files as $filename => $absolute_filename ) :
     203        $file_type = substr( $filename, strrpos( $filename, '.' ) );
     204
     205        if ( $file_type !== $previous_file_type ) {
     206            if ( '' !== $previous_file_type ) {
     207                echo "\t</ul>\n";
     208            }
     209
     210            switch ( $file_type ) {
     211                case '.php':
     212                    if ( $has_templates || $theme->parent() ) :
     213                        echo "\t<h2>" . __( 'Templates' ) . "</h2>\n";
     214                        if ( $theme->parent() ) {
     215                            echo '<p class="howto">' . sprintf( __( 'This child theme inherits templates from a parent theme, %s.' ),
     216                                sprintf( '<a href="%s">%s</a>',
     217                                    self_admin_url( 'theme-editor.php?theme=' . urlencode( $theme->get_template() ) ),
     218                                    $theme->parent()->display( 'Name' )
     219                                )
     220                            ) . "</p>\n";
     221                        }
     222                    endif;
     223                    break;
     224                case '.css':
     225                    echo "\t<h2>" . _x( 'Styles', 'Theme stylesheets in theme editor' ) . "</h2>\n";
     226                    break;
     227                default:
     228                    /* translators: %s: file extension */
     229                    echo "\t<h2>" . sprintf( __( '%s files' ), $file_type ) . "</h2>\n";
     230                    break;
     231            }
     232
     233            echo "\t<ul>\n";
     234        }
     235
     236        $file_description = get_file_description( $filename );
     237        if ( $filename !== basename( $absolute_filename ) || $file_description !== $filename ) {
     238            $file_description .= '<br /><span class="nonessential">(' . $filename . ')</span>';
     239        }
     240
     241        if ( $absolute_filename === $file ) {
     242            $file_description = '<span class="highlight">' . $file_description . '</span>';
     243        }
     244
     245        $previous_file_type = $file_type;
    243246?>
    244                 <li><a href="theme-editor.php?file=<?php echo urlencode( $filename ) ?>&amp;theme=<?php echo urlencode( $stylesheet ) ?>"><?php echo $file_description; ?></a></li>
     247        <li><a href="theme-editor.php?file=<?php echo urlencode( $filename ) ?>&amp;theme=<?php echo urlencode( $stylesheet ) ?>"><?php echo $file_description; ?></a></li>
    245248<?php
    246         endforeach;
     249    endforeach;
    247250?>
    248251</ul>
    249252<?php endif; ?>
    250253</div>
    251254<?php if ( $error ) :
    252         echo '<div class="error"><p>' . __('Oops, no such file exists! Double check the name and try again, merci.') . '</p></div>';
     255    echo '<div class="error"><p>' . __('Oops, no such file exists! Double check the name and try again, merci.') . '</p></div>';
    253256else : ?>
    254         <form name="template" id="template" action="theme-editor.php" method="post">
    255         <?php wp_nonce_field( 'edit-theme_' . $file . $stylesheet ); ?>
    256                 <div><textarea cols="70" rows="30" name="newcontent" id="newcontent" aria-describedby="newcontent-description"><?php echo $content; ?></textarea>
    257                 <input type="hidden" name="action" value="update" />
    258                 <input type="hidden" name="file" value="<?php echo esc_attr( $relative_file ); ?>" />
    259                 <input type="hidden" name="theme" value="<?php echo esc_attr( $theme->get_stylesheet() ); ?>" />
    260                 <input type="hidden" name="scrollto" id="scrollto" value="<?php echo $scrollto; ?>" />
    261                 </div>
    262         <?php if ( ! empty( $functions ) ) : ?>
    263                 <div id="documentation" class="hide-if-no-js">
    264                 <label for="docs-list"><?php _e('Documentation:') ?></label>
    265                 <?php echo $docs_select; ?>
    266                 <input type="button" class="button" value="<?php esc_attr_e( 'Look Up' ); ?>" onclick="if ( '' != jQuery('#docs-list').val() ) { window.open( 'https://api.wordpress.org/core/handbook/1.0/?function=' + escape( jQuery( '#docs-list' ).val() ) + '&amp;locale=<?php echo urlencode( get_user_locale() ) ?>&amp;version=<?php echo urlencode( get_bloginfo( 'version' ) ) ?>&amp;redirect=true'); }" />
    267                 </div>
    268         <?php endif; ?>
    269 
    270                 <div>
    271                 <?php if ( is_child_theme() && $theme->get_stylesheet() == get_template() ) : ?>
    272                         <p><?php if ( is_writeable( $file ) ) { ?><strong><?php _e( 'Caution:' ); ?></strong><?php } ?>
    273                         <?php _e( 'This is a file in your current parent theme.' ); ?></p>
    274                 <?php endif; ?>
     257    <form name="template" id="template" action="theme-editor.php" method="post">
     258    <?php wp_nonce_field( 'edit-theme_' . $file . $stylesheet ); ?>
     259        <div><textarea cols="70" rows="30" name="newcontent" id="newcontent" aria-describedby="newcontent-description"><?php echo $content; ?></textarea>
     260        <input type="hidden" name="action" value="update" />
     261        <input type="hidden" name="file" value="<?php echo esc_attr( $relative_file ); ?>" />
     262        <input type="hidden" name="theme" value="<?php echo esc_attr( $theme->get_stylesheet() ); ?>" />
     263        <input type="hidden" name="scrollto" id="scrollto" value="<?php echo $scrollto; ?>" />
     264        </div>
     265    <?php if ( ! empty( $functions ) ) : ?>
     266        <div id="documentation" class="hide-if-no-js">
     267        <label for="docs-list"><?php _e('Documentation:') ?></label>
     268        <?php echo $docs_select; ?>
     269        <input type="button" class="button" value="<?php esc_attr_e( 'Look Up' ); ?>" onclick="if ( '' != jQuery('#docs-list').val() ) { window.open( 'https://api.wordpress.org/core/handbook/1.0/?function=' + escape( jQuery( '#docs-list' ).val() ) + '&amp;locale=<?php echo urlencode( get_user_locale() ) ?>&amp;version=<?php echo urlencode( get_bloginfo( 'version' ) ) ?>&amp;redirect=true'); }" />
     270        </div>
     271    <?php endif; ?>
     272
     273        <div>
     274        <?php if ( is_child_theme() && $theme->get_stylesheet() == get_template() ) : ?>
     275            <p><?php if ( is_writeable( $file ) ) { ?><strong><?php _e( 'Caution:' ); ?></strong><?php } ?>
     276            <?php _e( 'This is a file in your current parent theme.' ); ?></p>
     277        <?php endif; ?>
    275278<?php
    276         if ( is_writeable( $file ) ) :
    277                 submit_button( __( 'Update File' ), 'primary', 'submit', true );
    278         else : ?>
     279    if ( is_writeable( $file ) ) :
     280        submit_button( __( 'Update File' ), 'primary', 'submit', true );
     281    else : ?>
    279282<p><em><?php _e('You need to make this file writable before you can save your changes. See <a href="https://codex.wordpress.org/Changing_File_Permissions">the Codex</a> for more information.'); ?></em></p>
    280283<?php endif; ?>
    281                 </div>
    282         </form>
     284        </div>
     285    </form>
    283286<?php
    284287endif; // $error
    285288?>
    endif; // $error 
    287290</div>
    288291<script type="text/javascript">
    289292jQuery(document).ready(function($){
    290         $('#template').submit(function(){ $('#scrollto').val( $('#newcontent').scrollTop() ); });
    291         $('#newcontent').scrollTop( $('#scrollto').val() );
     293    $('#template').submit(function(){ $('#scrollto').val( $('#newcontent').scrollTop() ); });
     294    $('#newcontent').scrollTop( $('#scrollto').val() );
    292295});
    293296</script>
    294297<?php
  • src/wp-admin/theme-install.php

    diff --git a/src/wp-admin/theme-install.php b/src/wp-admin/theme-install.php
    index dd9ff500d1..64054a3de1 100644
    a b  
    1010require_once( dirname( __FILE__ ) . '/admin.php' );
    1111require( ABSPATH . 'wp-admin/includes/theme-install.php' );
    1212
    13 wp_reset_vars( array( 'tab' ) );
     13$tab = wp_assign_request_var('tab');
    1414
    1515if ( ! current_user_can('install_themes') )
    16         wp_die( __( 'Sorry, you are not allowed to install themes on this site.' ) );
     16    wp_die( __( 'Sorry, you are not allowed to install themes on this site.' ) );
    1717
    1818if ( is_multisite() && ! is_network_admin() ) {
    19         wp_redirect( network_admin_url( 'theme-install.php' ) );
    20         exit();
     19    wp_redirect( network_admin_url( 'theme-install.php' ) );
     20    exit();
    2121}
    2222
    2323$title = __( 'Add Themes' );
    2424$parent_file = 'themes.php';
    2525
    2626if ( ! is_network_admin() ) {
    27         $submenu_file = 'themes.php';
     27    $submenu_file = 'themes.php';
    2828}
    2929
    3030$installed_themes = search_theme_directories();
    3131
    3232if ( false === $installed_themes ) {
    33         $installed_themes = array();
     33    $installed_themes = array();
    3434}
    3535
    3636foreach ( $installed_themes as $k => $v ) {
    37         if ( false !== strpos( $k, '/' ) ) {
    38                 unset( $installed_themes[ $k ] );
    39         }
     37    if ( false !== strpos( $k, '/' ) ) {
     38        unset( $installed_themes[ $k ] );
     39    }
    4040}
    4141
    4242wp_localize_script( 'theme', '_wpThemeSettings', array(
    43         'themes'   => false,
    44         'settings' => array(
    45                 'isInstall'  => true,
    46                 'canInstall' => current_user_can( 'install_themes' ),
    47                 'installURI' => current_user_can( 'install_themes' ) ? self_admin_url( 'theme-install.php' ) : null,
    48                 'adminUrl'   => parse_url( self_admin_url(), PHP_URL_PATH )
    49         ),
    50         'l10n' => array(
    51                 'addNew'              => __( 'Add New Theme' ),
    52                 'search'              => __( 'Search Themes' ),
    53                 'searchPlaceholder'   => __( 'Search themes...' ), // placeholder (no ellipsis)
    54                 'upload'              => __( 'Upload Theme' ),
    55                 'back'                => __( 'Back' ),
    56                 'error'               => sprintf(
    57                         /* translators: %s: support forums URL */
    58                         __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server&#8217;s configuration. If you continue to have problems, please try the <a href="%s">support forums</a>.' ),
    59                         __( 'https://wordpress.org/support/' )
    60                 ),
    61                 'themesFound'         => __( 'Number of Themes found: %d' ),
    62                 'noThemesFound'       => __( 'No themes found. Try a different search.' ),
    63                 'collapseSidebar'     => __( 'Collapse Sidebar' ),
    64                 'expandSidebar'       => __( 'Expand Sidebar' ),
    65                 /* translators: accessibility text */
    66                 'selectFeatureFilter' => __( 'Select one or more Theme features to filter by' ),
    67         ),
    68         'installedThemes' => array_keys( $installed_themes ),
     43    'themes'   => false,
     44    'settings' => array(
     45        'isInstall'  => true,
     46        'canInstall' => current_user_can( 'install_themes' ),
     47        'installURI' => current_user_can( 'install_themes' ) ? self_admin_url( 'theme-install.php' ) : null,
     48        'adminUrl'   => parse_url( self_admin_url(), PHP_URL_PATH )
     49    ),
     50    'l10n' => array(
     51        'addNew'              => __( 'Add New Theme' ),
     52        'search'              => __( 'Search Themes' ),
     53        'searchPlaceholder'   => __( 'Search themes...' ), // placeholder (no ellipsis)
     54        'upload'              => __( 'Upload Theme' ),
     55        'back'                => __( 'Back' ),
     56        'error'               => sprintf(
     57            /* translators: %s: support forums URL */
     58            __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server&#8217;s configuration. If you continue to have problems, please try the <a href="%s">support forums</a>.' ),
     59            __( 'https://wordpress.org/support/' )
     60        ),
     61        'themesFound'         => __( 'Number of Themes found: %d' ),
     62        'noThemesFound'       => __( 'No themes found. Try a different search.' ),
     63        'collapseSidebar'     => __( 'Collapse Sidebar' ),
     64        'expandSidebar'       => __( 'Expand Sidebar' ),
     65        /* translators: accessibility text */
     66        'selectFeatureFilter' => __( 'Select one or more Theme features to filter by' ),
     67    ),
     68    'installedThemes' => array_keys( $installed_themes ),
    6969) );
    7070
    7171wp_enqueue_script( 'theme' );
    7272wp_enqueue_script( 'updates' );
    7373
    7474if ( $tab ) {
    75         /**
    76         * Fires before each of the tabs are rendered on the Install Themes page.
    77         *
    78         * The dynamic portion of the hook name, `$tab`, refers to the current
    79         * theme install tab. Possible values are 'dashboard', 'search', 'upload',
    80         * 'featured', 'new', or 'updated'.
    81         *
    82         * @since 2.8.0
    83         */
    84         do_action( "install_themes_pre_{$tab}" );
     75    /**
     76    * Fires before each of the tabs are rendered on the Install Themes page.
     77    *
     78    * The dynamic portion of the hook name, `$tab`, refers to the current
     79    * theme install tab. Possible values are 'dashboard', 'search', 'upload',
     80    * 'featured', 'new', or 'updated'.
     81    *
     82    * @since 2.8.0
     83    */
     84    do_action( "install_themes_pre_{$tab}" );
    8585}
    8686
    8787$help_overview =
    88         '<p>' . sprintf(
    89                         /* translators: %s: Theme Directory URL */
    90                         __( 'You can find additional themes for your site by using the Theme Browser/Installer on this screen, which will display themes from the <a href="%s">WordPress Theme Directory</a>. These themes are designed and developed by third parties, are available free of charge, and are compatible with the license WordPress uses.' ),
    91                         __( 'https://wordpress.org/themes/' )
    92                 ) . '</p>' .
    93         '<p>' . __( 'You can Search for themes by keyword, author, or tag, or can get more specific and search by criteria listed in the feature filter.' ) . ' <span id="live-search-desc">' . __( 'The search results will be updated as you type.' ) . '</span></p>' .
    94         '<p>' . __( 'Alternately, you can browse the themes that are Featured, Popular, or Latest. When you find a theme you like, you can preview it or install it.' ) . '</p>' .
    95         '<p>' . sprintf(
    96                         /* translators: %s: /wp-content/themes */
    97                         __( 'You can Upload a theme manually if you have already downloaded its ZIP archive onto your computer (make sure it is from a trusted and original source). You can also do it the old-fashioned way and copy a downloaded theme&#8217;s folder via FTP into your %s directory.' ),
    98                         '<code>/wp-content/themes</code>'
    99                 ) . '</p>';
     88    '<p>' . sprintf(
     89            /* translators: %s: Theme Directory URL */
     90            __( 'You can find additional themes for your site by using the Theme Browser/Installer on this screen, which will display themes from the <a href="%s">WordPress Theme Directory</a>. These themes are designed and developed by third parties, are available free of charge, and are compatible with the license WordPress uses.' ),
     91            __( 'https://wordpress.org/themes/' )
     92        ) . '</p>' .
     93    '<p>' . __( 'You can Search for themes by keyword, author, or tag, or can get more specific and search by criteria listed in the feature filter.' ) . ' <span id="live-search-desc">' . __( 'The search results will be updated as you type.' ) . '</span></p>' .
     94    '<p>' . __( 'Alternately, you can browse the themes that are Featured, Popular, or Latest. When you find a theme you like, you can preview it or install it.' ) . '</p>' .
     95    '<p>' . sprintf(
     96            /* translators: %s: /wp-content/themes */
     97            __( 'You can Upload a theme manually if you have already downloaded its ZIP archive onto your computer (make sure it is from a trusted and original source). You can also do it the old-fashioned way and copy a downloaded theme&#8217;s folder via FTP into your %s directory.' ),
     98            '<code>/wp-content/themes</code>'
     99        ) . '</p>';
    100100
    101101get_current_screen()->add_help_tab( array(
    102         'id'      => 'overview',
    103         'title'   => __('Overview'),
    104         'content' => $help_overview
     102    'id'      => 'overview',
     103    'title'   => __('Overview'),
     104    'content' => $help_overview
    105105) );
    106106
    107107$help_installing =
    108         '<p>' . __('Once you have generated a list of themes, you can preview and install any of them. Click on the thumbnail of the theme you&#8217;re interested in previewing. It will open up in a full-screen Preview page to give you a better idea of how that theme will look.') . '</p>' .
    109         '<p>' . __('To install the theme so you can preview it with your site&#8217;s content and customize its theme options, click the "Install" button at the top of the left-hand pane. The theme files will be downloaded to your website automatically. When this is complete, the theme is now available for activation, which you can do by clicking the "Activate" link, or by navigating to your Manage Themes screen and clicking the "Live Preview" link under any installed theme&#8217;s thumbnail image.') . '</p>';
     108    '<p>' . __('Once you have generated a list of themes, you can preview and install any of them. Click on the thumbnail of the theme you&#8217;re interested in previewing. It will open up in a full-screen Preview page to give you a better idea of how that theme will look.') . '</p>' .
     109    '<p>' . __('To install the theme so you can preview it with your site&#8217;s content and customize its theme options, click the "Install" button at the top of the left-hand pane. The theme files will be downloaded to your website automatically. When this is complete, the theme is now available for activation, which you can do by clicking the "Activate" link, or by navigating to your Manage Themes screen and clicking the "Live Preview" link under any installed theme&#8217;s thumbnail image.') . '</p>';
    110110
    111111get_current_screen()->add_help_tab( array(
    112         'id'      => 'installing',
    113         'title'   => __('Previewing and Installing'),
    114         'content' => $help_installing
     112    'id'      => 'installing',
     113    'title'   => __('Previewing and Installing'),
     114    'content' => $help_installing
    115115) );
    116116
    117117get_current_screen()->set_help_sidebar(
    118         '<p><strong>' . __('For more information:') . '</strong></p>' .
    119         '<p>' . __('<a href="https://codex.wordpress.org/Using_Themes#Adding_New_Themes">Documentation on Adding New Themes</a>') . '</p>' .
    120         '<p>' . __('<a href="https://wordpress.org/support/">Support Forums</a>') . '</p>'
     118    '<p><strong>' . __('For more information:') . '</strong></p>' .
     119    '<p>' . __('<a href="https://codex.wordpress.org/Using_Themes#Adding_New_Themes">Documentation on Adding New Themes</a>') . '</p>' .
     120    '<p>' . __('<a href="https://wordpress.org/support/">Support Forums</a>') . '</p>'
    121121);
    122122
    123123include(ABSPATH . 'wp-admin/admin-header.php');
    124124
    125125?>
    126126<div class="wrap">
    127         <h1 class="wp-heading-inline"><?php echo esc_html( $title ); ?></h1>
    128 
    129         <?php
    130 
    131         /**
    132         * Filters the tabs shown on the Add Themes screen.
    133         *
    134         * This filter is for backward compatibility only, for the suppression of the upload tab.
    135         *
    136         * @since 2.8.0
    137         *
    138         * @param array $tabs The tabs shown on the Add Themes screen. Default is 'upload'.
    139         */
    140         $tabs = apply_filters( 'install_themes_tabs', array( 'upload' => __( 'Upload Theme' ) ) );
    141         if ( ! empty( $tabs['upload'] ) && current_user_can( 'upload_themes' ) ) {
    142                 echo ' <button type="button" class="upload-view-toggle page-title-action hide-if-no-js" aria-expanded="false">' . __( 'Upload Theme' ) . '</button>';
    143         }
    144         ?>
    145 
    146         <hr class="wp-header-end">
    147 
    148         <div class="error hide-if-js">
    149                 <p><?php _e( 'The Theme Installer screen requires JavaScript.' ); ?></p>
    150         </div>
    151 
    152         <div class="upload-theme">
    153         <?php install_themes_upload(); ?>
    154         </div>
    155 
    156         <h2 class="screen-reader-text hide-if-no-js"><?php _e( 'Filter themes list' ); ?></h2>
    157 
    158         <div class="wp-filter hide-if-no-js">
    159                 <div class="filter-count">
    160                         <span class="count theme-count"></span>
    161                 </div>
    162 
    163                 <ul class="filter-links">
    164                         <li><a href="#" data-sort="featured"><?php _ex( 'Featured', 'themes' ); ?></a></li>
    165                         <li><a href="#" data-sort="popular"><?php _ex( 'Popular', 'themes' ); ?></a></li>
    166                         <li><a href="#" data-sort="new"><?php _ex( 'Latest', 'themes' ); ?></a></li>
    167                         <li><a href="#" data-sort="favorites"><?php _ex( 'Favorites', 'themes' ); ?></a></li>
    168                 </ul>
    169 
    170                 <button type="button" class="button drawer-toggle" aria-expanded="false"><?php _e( 'Feature Filter' ); ?></button>
    171 
    172                 <form class="search-form"></form>
    173 
    174                 <div class="favorites-form">
    175                         <?php
    176                         $action = 'save_wporg_username_' . get_current_user_id();
    177                         if ( isset( $_GET['_wpnonce'] ) && wp_verify_nonce( wp_unslash( $_GET['_wpnonce'] ), $action ) ) {
    178                                 $user = isset( $_GET['user'] ) ? wp_unslash( $_GET['user'] ) : get_user_option( 'wporg_favorites' );
    179                                 update_user_meta( get_current_user_id(), 'wporg_favorites', $user );
    180                         } else {
    181                                 $user = get_user_option( 'wporg_favorites' );
    182                         }
    183                         ?>
    184                         <p class="install-help"><?php _e( 'If you have marked themes as favorites on WordPress.org, you can browse them here.' ); ?></p>
    185 
    186                         <p>
    187                                 <label for="wporg-username-input"><?php _e( 'Your WordPress.org username:' ); ?></label>
    188                                 <input type="hidden" id="wporg-username-nonce" name="_wpnonce" value="<?php echo esc_attr( wp_create_nonce( $action ) ); ?>" />
    189                                 <input type="search" id="wporg-username-input" value="<?php echo esc_attr( $user ); ?>" />
    190                                 <input type="button" class="button favorites-form-submit" value="<?php esc_attr_e( 'Get Favorites' ); ?>" />
    191                         </p>
    192                 </div>
    193 
    194                 <div class="filter-drawer">
    195                         <div class="buttons">
    196                                 <button type="button" class="apply-filters button"><?php _e( 'Apply Filters' ); ?><span></span></button>
    197                                 <button type="button" class="clear-filters button" aria-label="<?php esc_attr_e( 'Clear current filters' ); ?>"><?php _e( 'Clear' ); ?></button>
    198                         </div>
    199                 <?php
    200                 $feature_list = get_theme_feature_list();
    201                 foreach ( $feature_list as $feature_name => $features ) {
    202                         echo '<fieldset class="filter-group">';
    203                         $feature_name = esc_html( $feature_name );
    204                         echo '<legend>' . $feature_name . '</legend>';
    205                         echo '<div class="filter-group-feature">';
    206                         foreach ( $features as $feature => $feature_name ) {
    207                                 $feature = esc_attr( $feature );
    208                                 echo '<input type="checkbox" id="filter-id-' . $feature . '" value="' . $feature . '" /> ';
    209                                 echo '<label for="filter-id-' . $feature . '">' . $feature_name . '</label><br>';
    210                         }
    211                         echo '</div>';
    212                         echo '</fieldset>';
    213                 }
    214                 ?>
    215                         <div class="buttons">
    216                                 <button type="button" class="apply-filters button"><?php _e( 'Apply Filters' ); ?><span></span></button>
    217                                 <button type="button" class="clear-filters button" aria-label="<?php esc_attr_e( 'Clear current filters' ); ?>"><?php _e( 'Clear' ); ?></button>
    218                         </div>
    219                         <div class="filtered-by">
    220                                 <span><?php _e( 'Filtering by:' ); ?></span>
    221                                 <div class="tags"></div>
    222                                 <button type="button" class="button-link edit-filters"><?php _e( 'Edit Filters' ); ?></button>
    223                         </div>
    224                 </div>
    225         </div>
    226         <h2 class="screen-reader-text hide-if-no-js"><?php _e( 'Themes list' ); ?></h2>
    227         <div class="theme-browser content-filterable"></div>
    228         <div class="theme-install-overlay wp-full-overlay expanded"></div>
    229 
    230         <p class="no-themes"><?php _e( 'No themes found. Try a different search.' ); ?></p>
    231         <span class="spinner"></span>
     127    <h1 class="wp-heading-inline"><?php echo esc_html( $title ); ?></h1>
     128
     129    <?php
     130
     131    /**
     132    * Filters the tabs shown on the Add Themes screen.
     133    *
     134    * This filter is for backward compatibility only, for the suppression of the upload tab.
     135    *
     136    * @since 2.8.0
     137    *
     138    * @param array $tabs The tabs shown on the Add Themes screen. Default is 'upload'.
     139    */
     140    $tabs = apply_filters( 'install_themes_tabs', array( 'upload' => __( 'Upload Theme' ) ) );
     141    if ( ! empty( $tabs['upload'] ) && current_user_can( 'upload_themes' ) ) {
     142        echo ' <button type="button" class="upload-view-toggle page-title-action hide-if-no-js" aria-expanded="false">' . __( 'Upload Theme' ) . '</button>';
     143    }
     144    ?>
     145
     146    <hr class="wp-header-end">
     147
     148    <div class="error hide-if-js">
     149        <p><?php _e( 'The Theme Installer screen requires JavaScript.' ); ?></p>
     150    </div>
     151
     152    <div class="upload-theme">
     153    <?php install_themes_upload(); ?>
     154    </div>
     155
     156    <h2 class="screen-reader-text hide-if-no-js"><?php _e( 'Filter themes list' ); ?></h2>
     157
     158    <div class="wp-filter hide-if-no-js">
     159        <div class="filter-count">
     160            <span class="count theme-count"></span>
     161        </div>
     162
     163        <ul class="filter-links">
     164            <li><a href="#" data-sort="featured"><?php _ex( 'Featured', 'themes' ); ?></a></li>
     165            <li><a href="#" data-sort="popular"><?php _ex( 'Popular', 'themes' ); ?></a></li>
     166            <li><a href="#" data-sort="new"><?php _ex( 'Latest', 'themes' ); ?></a></li>
     167            <li><a href="#" data-sort="favorites"><?php _ex( 'Favorites', 'themes' ); ?></a></li>
     168        </ul>
     169
     170        <button type="button" class="button drawer-toggle" aria-expanded="false"><?php _e( 'Feature Filter' ); ?></button>
     171
     172        <form class="search-form"></form>
     173
     174        <div class="favorites-form">
     175            <?php
     176            $action = 'save_wporg_username_' . get_current_user_id();
     177            if ( isset( $_GET['_wpnonce'] ) && wp_verify_nonce( wp_unslash( $_GET['_wpnonce'] ), $action ) ) {
     178                $user = isset( $_GET['user'] ) ? wp_unslash( $_GET['user'] ) : get_user_option( 'wporg_favorites' );
     179                update_user_meta( get_current_user_id(), 'wporg_favorites', $user );
     180            } else {
     181                $user = get_user_option( 'wporg_favorites' );
     182            }
     183            ?>
     184            <p class="install-help"><?php _e( 'If you have marked themes as favorites on WordPress.org, you can browse them here.' ); ?></p>
     185
     186            <p>
     187                <label for="wporg-username-input"><?php _e( 'Your WordPress.org username:' ); ?></label>
     188                <input type="hidden" id="wporg-username-nonce" name="_wpnonce" value="<?php echo esc_attr( wp_create_nonce( $action ) ); ?>" />
     189                <input type="search" id="wporg-username-input" value="<?php echo esc_attr( $user ); ?>" />
     190                <input type="button" class="button favorites-form-submit" value="<?php esc_attr_e( 'Get Favorites' ); ?>" />
     191            </p>
     192        </div>
     193
     194        <div class="filter-drawer">
     195            <div class="buttons">
     196                <button type="button" class="apply-filters button"><?php _e( 'Apply Filters' ); ?><span></span></button>
     197                <button type="button" class="clear-filters button" aria-label="<?php esc_attr_e( 'Clear current filters' ); ?>"><?php _e( 'Clear' ); ?></button>
     198            </div>
     199        <?php
     200        $feature_list = get_theme_feature_list();
     201        foreach ( $feature_list as $feature_name => $features ) {
     202            echo '<fieldset class="filter-group">';
     203            $feature_name = esc_html( $feature_name );
     204            echo '<legend>' . $feature_name . '</legend>';
     205            echo '<div class="filter-group-feature">';
     206            foreach ( $features as $feature => $feature_name ) {
     207                $feature = esc_attr( $feature );
     208                echo '<input type="checkbox" id="filter-id-' . $feature . '" value="' . $feature . '" /> ';
     209                echo '<label for="filter-id-' . $feature . '">' . $feature_name . '</label><br>';
     210            }
     211            echo '</div>';
     212            echo '</fieldset>';
     213        }
     214        ?>
     215            <div class="buttons">
     216                <button type="button" class="apply-filters button"><?php _e( 'Apply Filters' ); ?><span></span></button>
     217                <button type="button" class="clear-filters button" aria-label="<?php esc_attr_e( 'Clear current filters' ); ?>"><?php _e( 'Clear' ); ?></button>
     218            </div>
     219            <div class="filtered-by">
     220                <span><?php _e( 'Filtering by:' ); ?></span>
     221                <div class="tags"></div>
     222                <button type="button" class="button-link edit-filters"><?php _e( 'Edit Filters' ); ?></button>
     223            </div>
     224        </div>
     225    </div>
     226    <h2 class="screen-reader-text hide-if-no-js"><?php _e( 'Themes list' ); ?></h2>
     227    <div class="theme-browser content-filterable"></div>
     228    <div class="theme-install-overlay wp-full-overlay expanded"></div>
     229
     230    <p class="no-themes"><?php _e( 'No themes found. Try a different search.' ); ?></p>
     231    <span class="spinner"></span>
    232232
    233233<?php
    234234if ( $tab ) {
    235         /**
    236         * Fires at the top of each of the tabs on the Install Themes page.
    237         *
    238         * The dynamic portion of the hook name, `$tab`, refers to the current
    239         * theme install tab. Possible values are 'dashboard', 'search', 'upload',
    240         * 'featured', 'new', or 'updated'.
    241         *
    242         * @since 2.8.0
    243         *
    244         * @param int $paged Number of the current page of results being viewed.
    245         */
    246         do_action( "install_themes_{$tab}", $paged );
     235    /**
     236    * Fires at the top of each of the tabs on the Install Themes page.
     237    *
     238    * The dynamic portion of the hook name, `$tab`, refers to the current
     239    * theme install tab. Possible values are 'dashboard', 'search', 'upload',
     240    * 'featured', 'new', or 'updated'.
     241    *
     242    * @since 2.8.0
     243    *
     244    * @param int $paged Number of the current page of results being viewed.
     245    */
     246    do_action( "install_themes_{$tab}", $paged );
    247247}
    248248?>
    249249</div>
    250250
    251251<script id="tmpl-theme" type="text/template">
    252         <# if ( data.screenshot_url ) { #>
    253                 <div class="theme-screenshot">
    254                         <img src="{{ data.screenshot_url }}" alt="" />
    255                 </div>
    256         <# } else { #>
    257                 <div class="theme-screenshot blank"></div>
    258         <# } #>
    259         <span class="more-details"><?php _ex( 'Details &amp; Preview', 'theme' ); ?></span>
    260         <div class="theme-author">
    261                 <?php
    262                 /* translators: %s: Theme author name */
    263                 printf( __( 'By %s' ), '{{ data.author }}' );
    264                 ?>
    265         </div>
    266         <h3 class="theme-name">{{ data.name }}</h3>
    267 
    268         <div class="theme-actions">
    269                 <# if ( data.installed ) { #>
    270                         <?php
    271                         /* translators: %s: Theme name */
    272                         $aria_label = sprintf( _x( 'Activate %s', 'theme' ), '{{ data.name }}' );
    273                         ?>
    274                         <# if ( data.activate_url ) { #>
    275                                 <a class="button button-primary activate" href="{{ data.activate_url }}" aria-label="<?php echo esc_attr( $aria_label ); ?>"><?php _e( 'Activate' ); ?></a>
    276                         <# } #>
    277                         <# if ( data.customize_url ) { #>
    278                                 <a class="button load-customize" href="{{ data.customize_url }}"><?php _e( 'Live Preview' ); ?></a>
    279                         <# } else { #>
    280                                 <button class="button preview install-theme-preview"><?php _e( 'Preview' ); ?></button>
    281                         <# } #>
    282                 <# } else { #>
    283                         <?php
    284                         /* translators: %s: Theme name */
    285                         $aria_label = sprintf( __( 'Install %s' ), '{{ data.name }}' );
    286                         ?>
    287                         <a class="button button-primary theme-install" data-name="{{ data.name }}" data-slug="{{ data.id }}" href="{{ data.install_url }}" aria-label="<?php echo esc_attr( $aria_label ); ?>"><?php _e( 'Install' ); ?></a>
    288                         <button class="button preview install-theme-preview"><?php _e( 'Preview' ); ?></button>
    289                 <# } #>
    290         </div>
    291 
    292         <# if ( data.installed ) { #>
    293                 <div class="notice notice-success notice-alt"><p><?php _ex( 'Installed', 'theme' ); ?></p></div>
    294         <# } #>
     252    <# if ( data.screenshot_url ) { #>
     253        <div class="theme-screenshot">
     254            <img src="{{ data.screenshot_url }}" alt="" />
     255        </div>
     256    <# } else { #>
     257        <div class="theme-screenshot blank"></div>
     258    <# } #>
     259    <span class="more-details"><?php _ex( 'Details &amp; Preview', 'theme' ); ?></span>
     260    <div class="theme-author">
     261        <?php
     262        /* translators: %s: Theme author name */
     263        printf( __( 'By %s' ), '{{ data.author }}' );
     264        ?>
     265    </div>
     266    <h3 class="theme-name">{{ data.name }}</h3>
     267
     268    <div class="theme-actions">
     269        <# if ( data.installed ) { #>
     270            <?php
     271            /* translators: %s: Theme name */
     272            $aria_label = sprintf( _x( 'Activate %s', 'theme' ), '{{ data.name }}' );
     273            ?>
     274            <# if ( data.activate_url ) { #>
     275                <a class="button button-primary activate" href="{{ data.activate_url }}" aria-label="<?php echo esc_attr( $aria_label ); ?>"><?php _e( 'Activate' ); ?></a>
     276            <# } #>
     277            <# if ( data.customize_url ) { #>
     278                <a class="button load-customize" href="{{ data.customize_url }}"><?php _e( 'Live Preview' ); ?></a>
     279            <# } else { #>
     280                <button class="button preview install-theme-preview"><?php _e( 'Preview' ); ?></button>
     281            <# } #>
     282        <# } else { #>
     283            <?php
     284            /* translators: %s: Theme name */
     285            $aria_label = sprintf( __( 'Install %s' ), '{{ data.name }}' );
     286            ?>
     287            <a class="button button-primary theme-install" data-name="{{ data.name }}" data-slug="{{ data.id }}" href="{{ data.install_url }}" aria-label="<?php echo esc_attr( $aria_label ); ?>"><?php _e( 'Install' ); ?></a>
     288            <button class="button preview install-theme-preview"><?php _e( 'Preview' ); ?></button>
     289        <# } #>
     290    </div>
     291
     292    <# if ( data.installed ) { #>
     293        <div class="notice notice-success notice-alt"><p><?php _ex( 'Installed', 'theme' ); ?></p></div>
     294    <# } #>
    295295</script>
    296296
    297297<script id="tmpl-theme-preview" type="text/template">
    298         <div class="wp-full-overlay-sidebar">
    299                 <div class="wp-full-overlay-header">
    300                         <button class="close-full-overlay"><span class="screen-reader-text"><?php _e( 'Close' ); ?></span></button>
    301                         <button class="previous-theme"><span class="screen-reader-text"><?php _ex( 'Previous', 'Button label for a theme' ); ?></span></button>
    302                         <button class="next-theme"><span class="screen-reader-text"><?php _ex( 'Next', 'Button label for a theme' ); ?></span></button>
    303                         <# if ( data.installed ) { #>
    304                                 <a class="button button-primary activate" href="{{ data.activate_url }}"><?php _e( 'Activate' ); ?></a>
    305                         <# } else { #>
    306                                 <a href="{{ data.install_url }}" class="button button-primary theme-install" data-name="{{ data.name }}" data-slug="{{ data.id }}"><?php _e( 'Install' ); ?></a>
    307                         <# } #>
    308                 </div>
    309                 <div class="wp-full-overlay-sidebar-content">
    310                         <div class="install-theme-info">
    311                                 <h3 class="theme-name">{{ data.name }}</h3>
    312                                         <span class="theme-by">
    313                                                 <?php
    314                                                 /* translators: %s: Theme author name */
    315                                                 printf( __( 'By %s' ), '{{ data.author }}' );
    316                                                 ?>
    317                                         </span>
    318 
    319                                         <img class="theme-screenshot" src="{{ data.screenshot_url }}" alt="" />
    320 
    321                                         <div class="theme-details">
    322                                                 <# if ( data.rating ) { #>
    323                                                         <div class="theme-rating">
    324                                                                 {{{ data.stars }}}
    325                                                                 <span class="num-ratings">({{ data.num_ratings }})</span>
    326                                                         </div>
    327                                                 <# } else { #>
    328                                                         <span class="no-rating"><?php _e( 'This theme has not been rated yet.' ); ?></span>
    329                                                 <# } #>
    330                                                 <div class="theme-version">
    331                                                         <?php
    332                                                         /* translators: %s: Theme version */
    333                                                         printf( __( 'Version: %s' ), '{{ data.version }}' );
    334                                                         ?>
    335                                                 </div>
    336                                                 <div class="theme-description">{{{ data.description }}}</div>
    337                                         </div>
    338                                 </div>
    339                         </div>
    340                         <div class="wp-full-overlay-footer">
    341                                 <button type="button" class="collapse-sidebar button" aria-expanded="true" aria-label="<?php esc_attr_e( 'Collapse Sidebar' ); ?>">
    342                                         <span class="collapse-sidebar-arrow"></span>
    343                                         <span class="collapse-sidebar-label"><?php _e( 'Collapse' ); ?></span>
    344                                 </button>
    345                         </div>
    346                 </div>
    347                 <div class="wp-full-overlay-main">
    348                 <iframe src="{{ data.preview_url }}" title="<?php esc_attr_e( 'Preview' ); ?>"></iframe>
    349         </div>
     298    <div class="wp-full-overlay-sidebar">
     299        <div class="wp-full-overlay-header">
     300            <button class="close-full-overlay"><span class="screen-reader-text"><?php _e( 'Close' ); ?></span></button>
     301            <button class="previous-theme"><span class="screen-reader-text"><?php _ex( 'Previous', 'Button label for a theme' ); ?></span></button>
     302            <button class="next-theme"><span class="screen-reader-text"><?php _ex( 'Next', 'Button label for a theme' ); ?></span></button>
     303            <# if ( data.installed ) { #>
     304                <a class="button button-primary activate" href="{{ data.activate_url }}"><?php _e( 'Activate' ); ?></a>
     305            <# } else { #>
     306                <a href="{{ data.install_url }}" class="button button-primary theme-install" data-name="{{ data.name }}" data-slug="{{ data.id }}"><?php _e( 'Install' ); ?></a>
     307            <# } #>
     308        </div>
     309        <div class="wp-full-overlay-sidebar-content">
     310            <div class="install-theme-info">
     311                <h3 class="theme-name">{{ data.name }}</h3>
     312                    <span class="theme-by">
     313                        <?php
     314                        /* translators: %s: Theme author name */
     315                        printf( __( 'By %s' ), '{{ data.author }}' );
     316                        ?>
     317                    </span>
     318
     319                    <img class="theme-screenshot" src="{{ data.screenshot_url }}" alt="" />
     320
     321                    <div class="theme-details">
     322                        <# if ( data.rating ) { #>
     323                            <div class="theme-rating">
     324                                {{{ data.stars }}}
     325                                <span class="num-ratings">({{ data.num_ratings }})</span>
     326                            </div>
     327                        <# } else { #>
     328                            <span class="no-rating"><?php _e( 'This theme has not been rated yet.' ); ?></span>
     329                        <# } #>
     330                        <div class="theme-version">
     331                            <?php
     332                            /* translators: %s: Theme version */
     333                            printf( __( 'Version: %s' ), '{{ data.version }}' );
     334                            ?>
     335                        </div>
     336                        <div class="theme-description">{{{ data.description }}}</div>
     337                    </div>
     338                </div>
     339            </div>
     340            <div class="wp-full-overlay-footer">
     341                <button type="button" class="collapse-sidebar button" aria-expanded="true" aria-label="<?php esc_attr_e( 'Collapse Sidebar' ); ?>">
     342                    <span class="collapse-sidebar-arrow"></span>
     343                    <span class="collapse-sidebar-label"><?php _e( 'Collapse' ); ?></span>
     344                </button>
     345            </div>
     346        </div>
     347        <div class="wp-full-overlay-main">
     348        <iframe src="{{ data.preview_url }}" title="<?php esc_attr_e( 'Preview' ); ?>"></iframe>
     349    </div>
    350350</script>
    351351
    352352<?php
  • src/wp-admin/themes.php

    diff --git a/src/wp-admin/themes.php b/src/wp-admin/themes.php
    index b73cd166d5..f972e32d5a 100644
    a b  
    1010require_once( dirname( __FILE__ ) . '/admin.php' );
    1111
    1212if ( ! current_user_can( 'switch_themes' ) && ! current_user_can( 'edit_theme_options' ) ) {
    13         wp_die(
    14                 '<h1>' . __( 'Cheatin&#8217; uh?' ) . '</h1>' .
    15                 '<p>' . __( 'Sorry, you are not allowed to edit theme options on this site.' ) . '</p>',
    16                 403
    17         );
     13    wp_die(
     14        '<h1>' . __( 'Cheatin&#8217; uh?' ) . '</h1>' .
     15        '<p>' . __( 'Sorry, you are not allowed to edit theme options on this site.' ) . '</p>',
     16        403
     17    );
    1818}
    1919
    2020if ( current_user_can( 'switch_themes' ) && isset($_GET['action'] ) ) {
    21         if ( 'activate' == $_GET['action'] ) {
    22                 check_admin_referer('switch-theme_' . $_GET['stylesheet']);
    23                 $theme = wp_get_theme( $_GET['stylesheet'] );
    24 
    25                 if ( ! $theme->exists() || ! $theme->is_allowed() ) {
    26                         wp_die(
    27                                 '<h1>' . __( 'Cheatin&#8217; uh?' ) . '</h1>' .
    28                                 '<p>' . __( 'The requested theme does not exist.' ) . '</p>',
    29                                 403
    30                         );
    31                 }
    32 
    33                 switch_theme( $theme->get_stylesheet() );
    34                 wp_redirect( admin_url('themes.php?activated=true') );
    35                 exit;
    36         } elseif ( 'delete' == $_GET['action'] ) {
    37                 check_admin_referer('delete-theme_' . $_GET['stylesheet']);
    38                 $theme = wp_get_theme( $_GET['stylesheet'] );
    39 
    40                 if ( ! current_user_can( 'delete_themes' ) ) {
    41                         wp_die(
    42                                 '<h1>' . __( 'Cheatin&#8217; uh?' ) . '</h1>' .
    43                                 '<p>' . __( 'Sorry, you are not allowed to delete this item.' ) . '</p>',
    44                                 403
    45                         );
    46                 }
    47 
    48                 if ( ! $theme->exists() ) {
    49                         wp_die(
    50                                 '<h1>' . __( 'Cheatin&#8217; uh?' ) . '</h1>' .
    51                                 '<p>' . __( 'The requested theme does not exist.' ) . '</p>',
    52                                 403
    53                         );
    54                 }
    55 
    56                 $active = wp_get_theme();
    57                 if ( $active->get( 'Template' ) == $_GET['stylesheet'] ) {
    58                         wp_redirect( admin_url( 'themes.php?delete-active-child=true' ) );
    59                 } else {
    60                         delete_theme( $_GET['stylesheet'] );
    61                         wp_redirect( admin_url( 'themes.php?deleted=true' ) );
    62                 }
    63                 exit;
    64         }
     21    if ( 'activate' == $_GET['action'] ) {
     22        check_admin_referer('switch-theme_' . $_GET['stylesheet']);
     23        $theme = wp_get_theme( $_GET['stylesheet'] );
     24
     25        if ( ! $theme->exists() || ! $theme->is_allowed() ) {
     26            wp_die(
     27                '<h1>' . __( 'Cheatin&#8217; uh?' ) . '</h1>' .
     28                '<p>' . __( 'The requested theme does not exist.' ) . '</p>',
     29                403
     30            );
     31        }
     32
     33        switch_theme( $theme->get_stylesheet() );
     34        wp_redirect( admin_url('themes.php?activated=true') );
     35        exit;
     36    } elseif ( 'delete' == $_GET['action'] ) {
     37        check_admin_referer('delete-theme_' . $_GET['stylesheet']);
     38        $theme = wp_get_theme( $_GET['stylesheet'] );
     39
     40        if ( ! current_user_can( 'delete_themes' ) ) {
     41            wp_die(
     42                '<h1>' . __( 'Cheatin&#8217; uh?' ) . '</h1>' .
     43                '<p>' . __( 'Sorry, you are not allowed to delete this item.' ) . '</p>',
     44                403
     45            );
     46        }
     47
     48        if ( ! $theme->exists() ) {
     49            wp_die(
     50                '<h1>' . __( 'Cheatin&#8217; uh?' ) . '</h1>' .
     51                '<p>' . __( 'The requested theme does not exist.' ) . '</p>',
     52                403
     53            );
     54        }
     55
     56        $active = wp_get_theme();
     57        if ( $active->get( 'Template' ) == $_GET['stylesheet'] ) {
     58            wp_redirect( admin_url( 'themes.php?delete-active-child=true' ) );
     59        } else {
     60            delete_theme( $_GET['stylesheet'] );
     61            wp_redirect( admin_url( 'themes.php?deleted=true' ) );
     62        }
     63        exit;
     64    }
    6565}
    6666
    6767$title = __('Manage Themes');
    $parent_file = 'themes.php'; 
    6969
    7070// Help tab: Overview
    7171if ( current_user_can( 'switch_themes' ) ) {
    72         $help_overview  = '<p>' . __( 'This screen is used for managing your installed themes. Aside from the default theme(s) included with your WordPress installation, themes are designed and developed by third parties.' ) . '</p>' .
    73                 '<p>' . __( 'From this screen you can:' ) . '</p>' .
    74                 '<ul><li>' . __( 'Hover or tap to see Activate and Live Preview buttons' ) . '</li>' .
    75                 '<li>' . __( 'Click on the theme to see the theme name, version, author, description, tags, and the Delete link' ) . '</li>' .
    76                 '<li>' . __( 'Click Customize for the current theme or Live Preview for any other theme to see a live preview' ) . '</li></ul>' .
    77                 '<p>' . __( 'The current theme is displayed highlighted as the first theme.' ) . '</p>' .
    78                 '<p>' . __( 'The search for installed themes will search for terms in their name, description, author, or tag.' ) . ' <span id="live-search-desc">' . __( 'The search results will be updated as you type.' ) . '</span></p>';
    79 
    80         get_current_screen()->add_help_tab( array(
    81                 'id'      => 'overview',
    82                 'title'   => __( 'Overview' ),
    83                 'content' => $help_overview
    84         ) );
     72    $help_overview  = '<p>' . __( 'This screen is used for managing your installed themes. Aside from the default theme(s) included with your WordPress installation, themes are designed and developed by third parties.' ) . '</p>' .
     73        '<p>' . __( 'From this screen you can:' ) . '</p>' .
     74        '<ul><li>' . __( 'Hover or tap to see Activate and Live Preview buttons' ) . '</li>' .
     75        '<li>' . __( 'Click on the theme to see the theme name, version, author, description, tags, and the Delete link' ) . '</li>' .
     76        '<li>' . __( 'Click Customize for the current theme or Live Preview for any other theme to see a live preview' ) . '</li></ul>' .
     77        '<p>' . __( 'The current theme is displayed highlighted as the first theme.' ) . '</p>' .
     78        '<p>' . __( 'The search for installed themes will search for terms in their name, description, author, or tag.' ) . ' <span id="live-search-desc">' . __( 'The search results will be updated as you type.' ) . '</span></p>';
     79
     80    get_current_screen()->add_help_tab( array(
     81        'id'      => 'overview',
     82        'title'   => __( 'Overview' ),
     83        'content' => $help_overview
     84    ) );
    8585} // switch_themes
    8686
    8787// Help tab: Adding Themes
    8888if ( current_user_can( 'install_themes' ) ) {
    89         if ( is_multisite() ) {
    90                 $help_install = '<p>' . __('Installing themes on Multisite can only be done from the Network Admin section.') . '</p>';
    91         } else {
    92                 $help_install = '<p>' . sprintf( __('If you would like to see more themes to choose from, click on the &#8220;Add New&#8221; button and you will be able to browse or search for additional themes from the <a href="%s">WordPress Theme Directory</a>. Themes in the WordPress Theme Directory are designed and developed by third parties, and are compatible with the license WordPress uses. Oh, and they&#8217;re free!'), __( 'https://wordpress.org/themes/' ) ) . '</p>';
    93         }
    94 
    95         get_current_screen()->add_help_tab( array(
    96                 'id'      => 'adding-themes',
    97                 'title'   => __('Adding Themes'),
    98                 'content' => $help_install
    99         ) );
     89    if ( is_multisite() ) {
     90        $help_install = '<p>' . __('Installing themes on Multisite can only be done from the Network Admin section.') . '</p>';
     91    } else {
     92        $help_install = '<p>' . sprintf( __('If you would like to see more themes to choose from, click on the &#8220;Add New&#8221; button and you will be able to browse or search for additional themes from the <a href="%s">WordPress Theme Directory</a>. Themes in the WordPress Theme Directory are designed and developed by third parties, and are compatible with the license WordPress uses. Oh, and they&#8217;re free!'), __( 'https://wordpress.org/themes/' ) ) . '</p>';
     93    }
     94
     95    get_current_screen()->add_help_tab( array(
     96        'id'      => 'adding-themes',
     97        'title'   => __('Adding Themes'),
     98        'content' => $help_install
     99    ) );
    100100} // install_themes
    101101
    102102// Help tab: Previewing and Customizing
    103103if ( current_user_can( 'edit_theme_options' ) && current_user_can( 'customize' ) ) {
    104         $help_customize =
    105                 '<p>' . __( 'Tap or hover on any theme then click the Live Preview button to see a live preview of that theme and change theme options in a separate, full-screen view. You can also find a Live Preview button at the bottom of the theme details screen. Any installed theme can be previewed and customized in this way.' ) . '</p>'.
    106                 '<p>' . __( 'The theme being previewed is fully interactive &mdash; navigate to different pages to see how the theme handles posts, archives, and other page templates. The settings may differ depending on what theme features the theme being previewed supports. To accept the new settings and activate the theme all in one step, click the Save &amp; Activate button above the menu.' ) . '</p>' .
    107                 '<p>' . __( 'When previewing on smaller monitors, you can use the collapse icon at the bottom of the left-hand pane. This will hide the pane, giving you more room to preview your site in the new theme. To bring the pane back, click on the collapse icon again.' ) . '</p>';
    108 
    109         get_current_screen()->add_help_tab( array(
    110                 'id'            => 'customize-preview-themes',
    111                 'title'         => __( 'Previewing and Customizing' ),
    112                 'content'       => $help_customize
    113         ) );
     104    $help_customize =
     105        '<p>' . __( 'Tap or hover on any theme then click the Live Preview button to see a live preview of that theme and change theme options in a separate, full-screen view. You can also find a Live Preview button at the bottom of the theme details screen. Any installed theme can be previewed and customized in this way.' ) . '</p>'.
     106        '<p>' . __( 'The theme being previewed is fully interactive &mdash; navigate to different pages to see how the theme handles posts, archives, and other page templates. The settings may differ depending on what theme features the theme being previewed supports. To accept the new settings and activate the theme all in one step, click the Save &amp; Activate button above the menu.' ) . '</p>' .
     107        '<p>' . __( 'When previewing on smaller monitors, you can use the collapse icon at the bottom of the left-hand pane. This will hide the pane, giving you more room to preview your site in the new theme. To bring the pane back, click on the collapse icon again.' ) . '</p>';
     108
     109    get_current_screen()->add_help_tab( array(
     110        'id'            => 'customize-preview-themes',
     111        'title'         => __( 'Previewing and Customizing' ),
     112        'content'       => $help_customize
     113    ) );
    114114} // edit_theme_options && customize
    115115
    116116get_current_screen()->set_help_sidebar(
    117         '<p><strong>' . __( 'For more information:' ) . '</strong></p>' .
    118         '<p>' . __( '<a href="https://codex.wordpress.org/Using_Themes">Documentation on Using Themes</a>' ) . '</p>' .
    119         '<p>' . __( '<a href="https://wordpress.org/support/">Support Forums</a>' ) . '</p>'
     117    '<p><strong>' . __( 'For more information:' ) . '</strong></p>' .
     118    '<p>' . __( '<a href="https://codex.wordpress.org/Using_Themes">Documentation on Using Themes</a>' ) . '</p>' .
     119    '<p>' . __( '<a href="https://wordpress.org/support/">Support Forums</a>' ) . '</p>'
    120120);
    121121
    122122if ( current_user_can( 'switch_themes' ) ) {
    123         $themes = wp_prepare_themes_for_js();
     123    $themes = wp_prepare_themes_for_js();
    124124} else {
    125         $themes = wp_prepare_themes_for_js( array( wp_get_theme() ) );
     125    $themes = wp_prepare_themes_for_js( array( wp_get_theme() ) );
    126126}
    127 wp_reset_vars( array( 'theme', 'search' ) );
     127
     128$theme = wp_assign_request_var('theme');
     129$search = wp_assign_request_var('search');
    128130
    129131wp_localize_script( 'theme', '_wpThemeSettings', array(
    130         'themes'   => $themes,
    131         'settings' => array(
    132                 'canInstall'    => ( ! is_multisite() && current_user_can( 'install_themes' ) ),
    133                 'installURI'    => ( ! is_multisite() && current_user_can( 'install_themes' ) ) ? admin_url( 'theme-install.php' ) : null,
    134                 'confirmDelete' => __( "Are you sure you want to delete this theme?\n\nClick 'Cancel' to go back, 'OK' to confirm the delete." ),
    135                 'adminUrl'      => parse_url( admin_url(), PHP_URL_PATH ),
    136         ),
    137         'l10n' => array(
    138                 'addNew'            => __( 'Add New Theme' ),
    139                 'search'            => __( 'Search Installed Themes' ),
    140                 'searchPlaceholder' => __( 'Search installed themes...' ), // placeholder (no ellipsis)
    141                 'themesFound'       => __( 'Number of Themes found: %d' ),
    142                 'noThemesFound'     => __( 'No themes found. Try a different search.' ),
    143         ),
     132    'themes'   => $themes,
     133    'settings' => array(
     134        'canInstall'    => ( ! is_multisite() && current_user_can( 'install_themes' ) ),
     135        'installURI'    => ( ! is_multisite() && current_user_can( 'install_themes' ) ) ? admin_url( 'theme-install.php' ) : null,
     136        'confirmDelete' => __( "Are you sure you want to delete this theme?\n\nClick 'Cancel' to go back, 'OK' to confirm the delete." ),
     137        'adminUrl'      => parse_url( admin_url(), PHP_URL_PATH ),
     138    ),
     139     'l10n' => array(
     140         'addNew'            => __( 'Add New Theme' ),
     141         'search'            => __( 'Search Installed Themes' ),
     142         'searchPlaceholder' => __( 'Search installed themes...' ), // placeholder (no ellipsis)
     143        'themesFound'       => __( 'Number of Themes found: %d' ),
     144        'noThemesFound'     => __( 'No themes found. Try a different search.' ),
     145      ),
    144146) );
    145147
    146148add_thickbox();
    require_once( ABSPATH . 'wp-admin/admin-header.php' ); 
    152154?>
    153155
    154156<div class="wrap">
    155         <h1 class="wp-heading-inline"><?php esc_html_e( 'Themes' ); ?>
    156                 <span class="title-count theme-count"><?php echo count( $themes ); ?></span>
    157         </h1>
     157    <h1 class="wp-heading-inline"><?php esc_html_e( 'Themes' ); ?>
     158        <span class="title-count theme-count"><?php echo count( $themes ); ?></span>
     159    </h1>
    158160
    159         <?php if ( ! is_multisite() && current_user_can( 'install_themes' ) ) : ?>
    160                 <a href="<?php echo admin_url( 'theme-install.php' ); ?>" class="hide-if-no-js page-title-action"><?php echo esc_html_x( 'Add New', 'Add new theme' ); ?></a>
    161         <?php endif; ?>
     161    <?php if ( ! is_multisite() && current_user_can( 'install_themes' ) ) : ?>
     162        <a href="<?php echo admin_url( 'theme-install.php' ); ?>" class="hide-if-no-js page-title-action"><?php echo esc_html_x( 'Add New', 'Add new theme' ); ?></a>
     163    <?php endif; ?>
    162164
    163         <form class="search-form"></form>
     165    <form class="search-form"></form>
    164166
    165         <hr class="wp-header-end">
     167    <hr class="wp-header-end">
    166168<?php
    167169if ( ! validate_current_theme() || isset( $_GET['broken'] ) ) : ?>
    168170<div id="message1" class="updated notice is-dismissible"><p><?php _e('The active theme is broken. Reverting to the default theme.'); ?></p></div>
    169171<?php elseif ( isset($_GET['activated']) ) :
    170                 if ( isset( $_GET['previewed'] ) ) { ?>
    171                 <div id="message2" class="updated notice is-dismissible"><p><?php _e( 'Settings saved and theme activated.' ); ?> <a href="<?php echo home_url( '/' ); ?>"><?php _e( 'Visit site' ); ?></a></p></div>
    172                 <?php } else { ?>
     172        if ( isset( $_GET['previewed'] ) ) { ?>
     173        <div id="message2" class="updated notice is-dismissible"><p><?php _e( 'Settings saved and theme activated.' ); ?> <a href="<?php echo home_url( '/' ); ?>"><?php _e( 'Visit site' ); ?></a></p></div>
     174        <?php } else { ?>
    173175<div id="message2" class="updated notice is-dismissible"><p><?php _e( 'New theme activated.' ); ?> <a href="<?php echo home_url( '/' ); ?>"><?php _e( 'Visit site' ); ?></a></p></div><?php
    174                 }
    175         elseif ( isset($_GET['deleted']) ) : ?>
     176        }
     177    elseif ( isset($_GET['deleted']) ) : ?>
    176178<div id="message3" class="updated notice is-dismissible"><p><?php _e('Theme deleted.') ?></p></div>
    177179<?php elseif ( isset( $_GET['delete-active-child'] ) ) : ?>
    178         <div id="message4" class="error"><p><?php _e( 'You cannot delete a theme while it has an active child theme.' ); ?></p></div>
     180    <div id="message4" class="error"><p><?php _e( 'You cannot delete a theme while it has an active child theme.' ); ?></p></div>
    179181<?php
    180182endif;
    181183
    182184$ct = wp_get_theme();
    183185
    184186if ( $ct->errors() && ( ! is_multisite() || current_user_can( 'manage_network_themes' ) ) ) {
    185         echo '<div class="error"><p>' . __( 'ERROR:' ) . ' ' . $ct->errors()->get_error_message() . '</p></div>';
     187    echo '<div class="error"><p>' . __( 'ERROR:' ) . ' ' . $ct->errors()->get_error_message() . '</p></div>';
    186188}
    187189
    188190/*
    189191// Certain error codes are less fatal than others. We can still display theme information in most cases.
    190192if ( ! $ct->errors() || ( 1 == count( $ct->errors()->get_error_codes() )
    191         && in_array( $ct->errors()->get_error_code(), array( 'theme_no_parent', 'theme_parent_invalid', 'theme_no_index' ) ) ) ) : ?>
     193    && in_array( $ct->errors()->get_error_code(), array( 'theme_no_parent', 'theme_parent_invalid', 'theme_no_index' ) ) ) ) : ?>
    192194*/
    193195
    194         // Pretend you didn't see this.
    195         $current_theme_actions = array();
    196         if ( is_array( $submenu ) && isset( $submenu['themes.php'] ) ) {
    197                 foreach ( (array) $submenu['themes.php'] as $item) {
    198                         $class = '';
    199                         if ( 'themes.php' == $item[2] || 'theme-editor.php' == $item[2] || 0 === strpos( $item[2], 'customize.php' ) )
    200                                 continue;
    201                         // 0 = name, 1 = capability, 2 = file
    202                         if ( ( strcmp($self, $item[2]) == 0 && empty($parent_file)) || ($parent_file && ($item[2] == $parent_file)) )
    203                                 $class = ' current';
    204                         if ( !empty($submenu[$item[2]]) ) {
    205                                 $submenu[$item[2]] = array_values($submenu[$item[2]]); // Re-index.
    206                                 $menu_hook = get_plugin_page_hook($submenu[$item[2]][0][2], $item[2]);
    207                                 if ( file_exists(WP_PLUGIN_DIR . "/{$submenu[$item[2]][0][2]}") || !empty($menu_hook))
    208                                         $current_theme_actions[] = "<a class='button$class' href='admin.php?page={$submenu[$item[2]][0][2]}'>{$item[0]}</a>";
    209                                 else
    210                                         $current_theme_actions[] = "<a class='button$class' href='{$submenu[$item[2]][0][2]}'>{$item[0]}</a>";
    211                         } elseif ( ! empty( $item[2] ) && current_user_can( $item[1] ) ) {
    212                                 $menu_file = $item[2];
    213 
    214                                 if ( current_user_can( 'customize' ) ) {
    215                                         if ( 'custom-header' === $menu_file ) {
    216                                                 $current_theme_actions[] = "<a class='button hide-if-no-customize$class' href='customize.php?autofocus[control]=header_image'>{$item[0]}</a>";
    217                                         } elseif ( 'custom-background' === $menu_file ) {
    218                                                 $current_theme_actions[] = "<a class='button hide-if-no-customize$class' href='customize.php?autofocus[control]=background_image'>{$item[0]}</a>";
    219                                         }
    220                                 }
    221 
    222                                 if ( false !== ( $pos = strpos( $menu_file, '?' ) ) ) {
    223                                         $menu_file = substr( $menu_file, 0, $pos );
    224                                 }
    225 
    226                                 if ( file_exists( ABSPATH . "wp-admin/$menu_file" ) ) {
    227                                         $current_theme_actions[] = "<a class='button$class' href='{$item[2]}'>{$item[0]}</a>";
    228                                 } else {
    229                                         $current_theme_actions[] = "<a class='button$class' href='themes.php?page={$item[2]}'>{$item[0]}</a>";
    230                                 }
    231                         }
    232                 }
    233         }
     196    // Pretend you didn't see this.
     197    $current_theme_actions = array();
     198    if ( is_array( $submenu ) && isset( $submenu['themes.php'] ) ) {
     199        foreach ( (array) $submenu['themes.php'] as $item) {
     200            $class = '';
     201            if ( 'themes.php' == $item[2] || 'theme-editor.php' == $item[2] || 0 === strpos( $item[2], 'customize.php' ) )
     202                continue;
     203            // 0 = name, 1 = capability, 2 = file
     204            if ( ( strcmp($self, $item[2]) == 0 && empty($parent_file)) || ($parent_file && ($item[2] == $parent_file)) )
     205                $class = ' current';
     206            if ( !empty($submenu[$item[2]]) ) {
     207                $submenu[$item[2]] = array_values($submenu[$item[2]]); // Re-index.
     208                $menu_hook = get_plugin_page_hook($submenu[$item[2]][0][2], $item[2]);
     209                if ( file_exists(WP_PLUGIN_DIR . "/{$submenu[$item[2]][0][2]}") || !empty($menu_hook))
     210                    $current_theme_actions[] = "<a class='button$class' href='admin.php?page={$submenu[$item[2]][0][2]}'>{$item[0]}</a>";
     211                else
     212                    $current_theme_actions[] = "<a class='button$class' href='{$submenu[$item[2]][0][2]}'>{$item[0]}</a>";
     213            } elseif ( ! empty( $item[2] ) && current_user_can( $item[1] ) ) {
     214                $menu_file = $item[2];
     215
     216                if ( current_user_can( 'customize' ) ) {
     217                    if ( 'custom-header' === $menu_file ) {
     218                        $current_theme_actions[] = "<a class='button hide-if-no-customize$class' href='customize.php?autofocus[control]=header_image'>{$item[0]}</a>";
     219                    } elseif ( 'custom-background' === $menu_file ) {
     220                        $current_theme_actions[] = "<a class='button hide-if-no-customize$class' href='customize.php?autofocus[control]=background_image'>{$item[0]}</a>";
     221                    }
     222                }
     223
     224                if ( false !== ( $pos = strpos( $menu_file, '?' ) ) ) {
     225                    $menu_file = substr( $menu_file, 0, $pos );
     226                }
     227
     228                if ( file_exists( ABSPATH . "wp-admin/$menu_file" ) ) {
     229                    $current_theme_actions[] = "<a class='button$class' href='{$item[2]}'>{$item[0]}</a>";
     230                } else {
     231                    $current_theme_actions[] = "<a class='button$class' href='themes.php?page={$item[2]}'>{$item[0]}</a>";
     232                }
     233            }
     234        }
     235    }
    234236
    235237?>
    236238
    237239<div class="theme-browser">
    238         <div class="themes wp-clearfix">
     240    <div class="themes wp-clearfix">
    239241
    240242<?php
    241243/*
    if ( ! $ct->errors() || ( 1 == count( $ct->errors()->get_error_codes() ) 
    243245 */
    244246
    245247foreach ( $themes as $theme ) :
    246         $aria_action = esc_attr( $theme['id'] . '-action' );
    247         $aria_name   = esc_attr( $theme['id'] . '-name' );
    248         ?>
     248    $aria_action = esc_attr( $theme['id'] . '-action' );
     249    $aria_name   = esc_attr( $theme['id'] . '-name' );
     250    ?>
    249251<div class="theme<?php if ( $theme['active'] ) echo ' active'; ?>" tabindex="0" aria-describedby="<?php echo $aria_action . ' ' . $aria_name; ?>">
    250         <?php if ( ! empty( $theme['screenshot'][0] ) ) { ?>
    251                 <div class="theme-screenshot">
    252                         <img src="<?php echo $theme['screenshot'][0]; ?>" alt="" />
    253                 </div>
    254         <?php } else { ?>
    255                 <div class="theme-screenshot blank"></div>
    256         <?php } ?>
    257 
    258         <?php if ( $theme['hasUpdate'] ) : ?>
    259                 <div class="update-message notice inline notice-warning notice-alt">
    260                 <?php if ( $theme['hasPackage'] ) : ?>
    261                         <p><?php _e( 'New version available. <button class="button-link" type="button">Update now</button>' ); ?></p>
    262                 <?php else : ?>
    263                         <p><?php _e( 'New version available.' ); ?></p>
    264                 <?php endif; ?>
    265                 </div>
    266         <?php endif; ?>
    267 
    268         <span class="more-details" id="<?php echo $aria_action; ?>"><?php _e( 'Theme Details' ); ?></span>
    269         <div class="theme-author"><?php printf( __( 'By %s' ), $theme['author'] ); ?></div>
    270 
    271         <?php if ( $theme['active'] ) { ?>
    272                 <h2 class="theme-name" id="<?php echo $aria_name; ?>">
    273                         <?php
    274                         /* translators: %s: theme name */
    275                         printf( __( '<span>Active:</span> %s' ), $theme['name'] );
    276                         ?>
    277                 </h2>
    278         <?php } else { ?>
    279                 <h2 class="theme-name" id="<?php echo $aria_name; ?>"><?php echo $theme['name']; ?></h2>
    280         <?php } ?>
    281 
    282         <div class="theme-actions">
    283 
    284         <?php if ( $theme['active'] ) { ?>
    285                 <?php if ( $theme['actions']['customize'] && current_user_can( 'edit_theme_options' ) && current_user_can( 'customize' ) ) { ?>
    286                         <a class="button button-primary customize load-customize hide-if-no-customize" href="<?php echo $theme['actions']['customize']; ?>"><?php _e( 'Customize' ); ?></a>
    287                 <?php } ?>
    288         <?php } else { ?>
    289                 <?php
    290                 /* translators: %s: Theme name */
    291                 $aria_label = sprintf( _x( 'Activate %s', 'theme' ), '{{ data.name }}' );
    292                 ?>
    293                 <a class="button activate" href="<?php echo $theme['actions']['activate']; ?>" aria-label="<?php echo esc_attr( $aria_label ); ?>"><?php _e( 'Activate' ); ?></a>
    294                 <?php if ( current_user_can( 'edit_theme_options' ) && current_user_can( 'customize' ) ) { ?>
    295                         <a class="button button-primary load-customize hide-if-no-customize" href="<?php echo $theme['actions']['customize']; ?>"><?php _e( 'Live Preview' ); ?></a>
    296                 <?php } ?>
    297         <?php } ?>
    298 
    299         </div>
     252    <?php if ( ! empty( $theme['screenshot'][0] ) ) { ?>
     253        <div class="theme-screenshot">
     254            <img src="<?php echo $theme['screenshot'][0]; ?>" alt="" />
     255        </div>
     256    <?php } else { ?>
     257        <div class="theme-screenshot blank"></div>
     258    <?php } ?>
     259
     260    <?php if ( $theme['hasUpdate'] ) : ?>
     261        <div class="update-message notice inline notice-warning notice-alt">
     262        <?php if ( $theme['hasPackage'] ) : ?>
     263            <p><?php _e( 'New version available. <button class="button-link" type="button">Update now</button>' ); ?></p>
     264        <?php else : ?>
     265            <p><?php _e( 'New version available.' ); ?></p>
     266        <?php endif; ?>
     267        </div>
     268    <?php endif; ?>
     269
     270    <span class="more-details" id="<?php echo $aria_action; ?>"><?php _e( 'Theme Details' ); ?></span>
     271    <div class="theme-author"><?php printf( __( 'By %s' ), $theme['author'] ); ?></div>
     272
     273    <?php if ( $theme['active'] ) { ?>
     274        <h2 class="theme-name" id="<?php echo $aria_name; ?>">
     275            <?php
     276            /* translators: %s: theme name */
     277            printf( __( '<span>Active:</span> %s' ), $theme['name'] );
     278            ?>
     279        </h2>
     280    <?php } else { ?>
     281        <h2 class="theme-name" id="<?php echo $aria_name; ?>"><?php echo $theme['name']; ?></h2>
     282    <?php } ?>
     283
     284    <div class="theme-actions">
     285
     286    <?php if ( $theme['active'] ) { ?>
     287        <?php if ( $theme['actions']['customize'] && current_user_can( 'edit_theme_options' ) && current_user_can( 'customize' ) ) { ?>
     288            <a class="button button-primary customize load-customize hide-if-no-customize" href="<?php echo $theme['actions']['customize']; ?>"><?php _e( 'Customize' ); ?></a>
     289        <?php } ?>
     290    <?php } else { ?>
     291        <?php
     292        /* translators: %s: Theme name */
     293        $aria_label = sprintf( _x( 'Activate %s', 'theme' ), '{{ data.name }}' );
     294        ?>
     295        <a class="button activate" href="<?php echo $theme['actions']['activate']; ?>" aria-label="<?php echo esc_attr( $aria_label ); ?>"><?php _e( 'Activate' ); ?></a>
     296        <?php if ( current_user_can( 'edit_theme_options' ) && current_user_can( 'customize' ) ) { ?>
     297            <a class="button button-primary load-customize hide-if-no-customize" href="<?php echo $theme['actions']['customize']; ?>"><?php _e( 'Live Preview' ); ?></a>
     298        <?php } ?>
     299    <?php } ?>
     300
     301    </div>
    300302</div>
    301303<?php endforeach; ?>
    302         </div>
     304    </div>
    303305</div>
    304306<div class="theme-overlay"></div>
    305307
    $can_delete = current_user_can( 'delete_themes' ); 
    319321$can_install = current_user_can( 'install_themes' );
    320322?>
    321323<table>
    322         <tr>
    323                 <th><?php _ex('Name', 'theme name'); ?></th>
    324                 <th><?php _e('Description'); ?></th>
    325                 <?php if ( $can_delete ) { ?>
    326                         <td></td>
    327                 <?php } ?>
    328                 <?php if ( $can_install ) { ?>
    329                         <td></td>
    330                 <?php } ?>
    331         </tr>
    332         <?php foreach ( $broken_themes as $broken_theme ) : ?>
    333                 <tr>
    334                         <td><?php echo $broken_theme->get( 'Name' ) ? $broken_theme->display( 'Name' ) : $broken_theme->get_stylesheet(); ?></td>
    335                         <td><?php echo $broken_theme->errors()->get_error_message(); ?></td>
    336                         <?php
    337                         if ( $can_delete ) {
    338                                 $stylesheet = $broken_theme->get_stylesheet();
    339                                 $delete_url = add_query_arg( array(
    340                                         'action'     => 'delete',
    341                                         'stylesheet' => urlencode( $stylesheet ),
    342                                 ), admin_url( 'themes.php' ) );
    343                                 $delete_url = wp_nonce_url( $delete_url, 'delete-theme_' . $stylesheet );
    344                                 ?>
    345                                 <td><a href="<?php echo esc_url( $delete_url ); ?>" class="button delete-theme"><?php _e( 'Delete' ); ?></a></td>
    346                                 <?php
    347                         }
    348 
    349                         if ( $can_install && 'theme_no_parent' === $broken_theme->errors()->get_error_code() ) {
    350                                 $parent_theme_name = $broken_theme->get( 'Template' );
    351                                 $parent_theme = themes_api( 'theme_information', array( 'slug' => urlencode( $parent_theme_name ) ) );
    352 
    353                                 if ( ! is_wp_error( $parent_theme ) ) {
    354                                         $install_url = add_query_arg( array(
    355                                                 'action' => 'install-theme',
    356                                                 'theme'  => urlencode( $parent_theme_name ),
    357                                         ), admin_url( 'update.php' ) );
    358                                         $install_url = wp_nonce_url( $install_url, 'install-theme_' . $parent_theme_name );
    359                                         ?>
    360                                         <td><a href="<?php echo esc_url( $install_url ); ?>" class="button install-theme"><?php _e( 'Install Parent Theme' ); ?></a></td>
    361                                         <?php
    362                                 }
    363                         }
    364                         ?>
    365                 </tr>
    366         <?php endforeach; ?>
     324    <tr>
     325        <th><?php _ex('Name', 'theme name'); ?></th>
     326        <th><?php _e('Description'); ?></th>
     327        <?php if ( $can_delete ) { ?>
     328            <td></td>
     329        <?php } ?>
     330        <?php if ( $can_install ) { ?>
     331            <td></td>
     332        <?php } ?>
     333    </tr>
     334    <?php foreach ( $broken_themes as $broken_theme ) : ?>
     335        <tr>
     336            <td><?php echo $broken_theme->get( 'Name' ) ? $broken_theme->display( 'Name' ) : $broken_theme->get_stylesheet(); ?></td>
     337            <td><?php echo $broken_theme->errors()->get_error_message(); ?></td>
     338            <?php
     339            if ( $can_delete ) {
     340                $stylesheet = $broken_theme->get_stylesheet();
     341                $delete_url = add_query_arg( array(
     342                    'action'     => 'delete',
     343                    'stylesheet' => urlencode( $stylesheet ),
     344                ), admin_url( 'themes.php' ) );
     345                $delete_url = wp_nonce_url( $delete_url, 'delete-theme_' . $stylesheet );
     346                ?>
     347                <td><a href="<?php echo esc_url( $delete_url ); ?>" class="button delete-theme"><?php _e( 'Delete' ); ?></a></td>
     348                <?php
     349            }
     350
     351            if ( $can_install && 'theme_no_parent' === $broken_theme->errors()->get_error_code() ) {
     352                $parent_theme_name = $broken_theme->get( 'Template' );
     353                $parent_theme = themes_api( 'theme_information', array( 'slug' => urlencode( $parent_theme_name ) ) );
     354
     355                if ( ! is_wp_error( $parent_theme ) ) {
     356                    $install_url = add_query_arg( array(
     357                        'action' => 'install-theme',
     358                        'theme'  => urlencode( $parent_theme_name ),
     359                    ), admin_url( 'update.php' ) );
     360                    $install_url = wp_nonce_url( $install_url, 'install-theme_' . $parent_theme_name );
     361                    ?>
     362                    <td><a href="<?php echo esc_url( $install_url ); ?>" class="button install-theme"><?php _e( 'Install Parent Theme' ); ?></a></td>
     363                    <?php
     364                }
     365            }
     366            ?>
     367        </tr>
     368    <?php endforeach; ?>
    367369</table>
    368370</div>
    369371
    $can_install = current_user_can( 'install_themes' ); 
    378380 */
    379381?>
    380382<script id="tmpl-theme" type="text/template">
    381         <# if ( data.screenshot[0] ) { #>
    382                 <div class="theme-screenshot">
    383                         <img src="{{ data.screenshot[0] }}" alt="" />
    384                 </div>
    385         <# } else { #>
    386                 <div class="theme-screenshot blank"></div>
    387         <# } #>
    388 
    389         <# if ( data.hasUpdate ) { #>
    390                 <# if ( data.hasPackage ) { #>
    391                         <div class="update-message notice inline notice-warning notice-alt"><p><?php _e( 'New version available. <button class="button-link" type="button">Update now</button>' ); ?></p></div>
    392                 <# } else { #>
    393                         <div class="update-message notice inline notice-warning notice-alt"><p><?php _e( 'New version available.' ); ?></p></div>
    394                 <# } #>
    395         <# } #>
    396 
    397         <span class="more-details" id="{{ data.id }}-action"><?php _e( 'Theme Details' ); ?></span>
    398         <div class="theme-author">
    399                 <?php
    400                 /* translators: %s: Theme author name */
    401                 printf( __( 'By %s' ), '{{{ data.author }}}' );
    402                 ?>
    403         </div>
    404 
    405         <# if ( data.active ) { #>
    406                 <h2 class="theme-name" id="{{ data.id }}-name">
    407                         <?php
    408                         /* translators: %s: Theme name */
    409                         printf( __( '<span>Active:</span> %s' ), '{{{ data.name }}}' );
    410                         ?>
    411                 </h2>
    412         <# } else { #>
    413                 <h2 class="theme-name" id="{{ data.id }}-name">{{{ data.name }}}</h2>
    414         <# } #>
    415 
    416         <div class="theme-actions">
    417                 <# if ( data.active ) { #>
    418                         <# if ( data.actions.customize ) { #>
    419                                 <a class="button button-primary customize load-customize hide-if-no-customize" href="{{{ data.actions.customize }}}"><?php _e( 'Customize' ); ?></a>
    420                         <# } #>
    421                 <# } else { #>
    422                         <?php
    423                         /* translators: %s: Theme name */
    424                         $aria_label = sprintf( _x( 'Activate %s', 'theme' ), '{{ data.name }}' );
    425                         ?>
    426                         <a class="button activate" href="{{{ data.actions.activate }}}" aria-label="<?php echo $aria_label; ?>"><?php _e( 'Activate' ); ?></a>
    427                         <a class="button button-primary load-customize hide-if-no-customize" href="{{{ data.actions.customize }}}"><?php _e( 'Live Preview' ); ?></a>
    428                 <# } #>
    429         </div>
     383    <# if ( data.screenshot[0] ) { #>
     384        <div class="theme-screenshot">
     385            <img src="{{ data.screenshot[0] }}" alt="" />
     386        </div>
     387    <# } else { #>
     388        <div class="theme-screenshot blank"></div>
     389    <# } #>
     390
     391    <# if ( data.hasUpdate ) { #>
     392        <# if ( data.hasPackage ) { #>
     393            <div class="update-message notice inline notice-warning notice-alt"><p><?php _e( 'New version available. <button class="button-link" type="button">Update now</button>' ); ?></p></div>
     394        <# } else { #>
     395            <div class="update-message notice inline notice-warning notice-alt"><p><?php _e( 'New version available.' ); ?></p></div>
     396        <# } #>
     397    <# } #>
     398
     399    <span class="more-details" id="{{ data.id }}-action"><?php _e( 'Theme Details' ); ?></span>
     400    <div class="theme-author">
     401        <?php
     402        /* translators: %s: Theme author name */
     403        printf( __( 'By %s' ), '{{{ data.author }}}' );
     404        ?>
     405    </div>
     406
     407    <# if ( data.active ) { #>
     408        <h2 class="theme-name" id="{{ data.id }}-name">
     409            <?php
     410            /* translators: %s: Theme name */
     411            printf( __( '<span>Active:</span> %s' ), '{{{ data.name }}}' );
     412            ?>
     413        </h2>
     414    <# } else { #>
     415        <h2 class="theme-name" id="{{ data.id }}-name">{{{ data.name }}}</h2>
     416    <# } #>
     417
     418    <div class="theme-actions">
     419        <# if ( data.active ) { #>
     420            <# if ( data.actions.customize ) { #>
     421                <a class="button button-primary customize load-customize hide-if-no-customize" href="{{{ data.actions.customize }}}"><?php _e( 'Customize' ); ?></a>
     422            <# } #>
     423        <# } else { #>
     424            <?php
     425            /* translators: %s: Theme name */
     426            $aria_label = sprintf( _x( 'Activate %s', 'theme' ), '{{ data.name }}' );
     427            ?>
     428            <a class="button activate" href="{{{ data.actions.activate }}}" aria-label="<?php echo $aria_label; ?>"><?php _e( 'Activate' ); ?></a>
     429            <a class="button button-primary load-customize hide-if-no-customize" href="{{{ data.actions.customize }}}"><?php _e( 'Live Preview' ); ?></a>
     430        <# } #>
     431    </div>
    430432</script>
    431433
    432434<script id="tmpl-theme-single" type="text/template">
    433         <div class="theme-backdrop"></div>
    434         <div class="theme-wrap wp-clearfix">
    435                 <div class="theme-header">
    436                         <button class="left dashicons dashicons-no"><span class="screen-reader-text"><?php _e( 'Show previous theme' ); ?></span></button>
    437                         <button class="right dashicons dashicons-no"><span class="screen-reader-text"><?php _e( 'Show next theme' ); ?></span></button>
    438                         <button class="close dashicons dashicons-no"><span class="screen-reader-text"><?php _e( 'Close details dialog' ); ?></span></button>
    439                 </div>
    440                 <div class="theme-about wp-clearfix">
    441                         <div class="theme-screenshots">
    442                         <# if ( data.screenshot[0] ) { #>
    443                                 <div class="screenshot"><img src="{{ data.screenshot[0] }}" alt="" /></div>
    444                         <# } else { #>
    445                                 <div class="screenshot blank"></div>
    446                         <# } #>
    447                         </div>
    448 
    449                         <div class="theme-info">
    450                                 <# if ( data.active ) { #>
    451                                         <span class="current-label"><?php _e( 'Current Theme' ); ?></span>
    452                                 <# } #>
    453                                 <h2 class="theme-name">{{{ data.name }}}<span class="theme-version"><?php printf( __( 'Version: %s' ), '{{ data.version }}' ); ?></span></h2>
    454                                 <p class="theme-author"><?php printf( __( 'By %s' ), '{{{ data.authorAndUri }}}' ); ?></p>
    455 
    456                                 <# if ( data.hasUpdate ) { #>
    457                                 <div class="notice notice-warning notice-alt notice-large">
    458                                         <h3 class="notice-title"><?php _e( 'Update Available' ); ?></h3>
    459                                         {{{ data.update }}}
    460                                 </div>
    461                                 <# } #>
    462                                 <p class="theme-description">{{{ data.description }}}</p>
    463 
    464                                 <# if ( data.parent ) { #>
    465                                         <p class="parent-theme"><?php printf( __( 'This is a child theme of %s.' ), '<strong>{{{ data.parent }}}</strong>' ); ?></p>
    466                                 <# } #>
    467 
    468                                 <# if ( data.tags ) { #>
    469                                         <p class="theme-tags"><span><?php _e( 'Tags:' ); ?></span> {{{ data.tags }}}</p>
    470                                 <# } #>
    471                         </div>
    472                 </div>
    473 
    474                 <div class="theme-actions">
    475                         <div class="active-theme">
    476                                 <a href="{{{ data.actions.customize }}}" class="button button-primary customize load-customize hide-if-no-customize"><?php _e( 'Customize' ); ?></a>
    477                                 <?php echo implode( ' ', $current_theme_actions ); ?>
    478                         </div>
    479                         <div class="inactive-theme">
    480                                 <?php
    481                                 /* translators: %s: Theme name */
    482                                 $aria_label = sprintf( _x( 'Activate %s', 'theme' ), '{{ data.name }}' );
    483                                 ?>
    484                                 <# if ( data.actions.activate ) { #>
    485                                         <a href="{{{ data.actions.activate }}}" class="button activate" aria-label="<?php echo $aria_label; ?>"><?php _e( 'Activate' ); ?></a>
    486                                 <# } #>
    487                                 <a href="{{{ data.actions.customize }}}" class="button button-primary load-customize hide-if-no-customize"><?php _e( 'Live Preview' ); ?></a>
    488                         </div>
    489 
    490                         <# if ( ! data.active && data.actions['delete'] ) { #>
    491                                 <a href="{{{ data.actions['delete'] }}}" class="button delete-theme"><?php _e( 'Delete' ); ?></a>
    492                         <# } #>
    493                 </div>
    494         </div>
     435    <div class="theme-backdrop"></div>
     436    <div class="theme-wrap wp-clearfix">
     437        <div class="theme-header">
     438            <button class="left dashicons dashicons-no"><span class="screen-reader-text"><?php _e( 'Show previous theme' ); ?></span></button>
     439            <button class="right dashicons dashicons-no"><span class="screen-reader-text"><?php _e( 'Show next theme' ); ?></span></button>
     440            <button class="close dashicons dashicons-no"><span class="screen-reader-text"><?php _e( 'Close details dialog' ); ?></span></button>
     441        </div>
     442        <div class="theme-about wp-clearfix">
     443            <div class="theme-screenshots">
     444            <# if ( data.screenshot[0] ) { #>
     445                <div class="screenshot"><img src="{{ data.screenshot[0] }}" alt="" /></div>
     446            <# } else { #>
     447                <div class="screenshot blank"></div>
     448            <# } #>
     449            </div>
     450
     451            <div class="theme-info">
     452                <# if ( data.active ) { #>
     453                    <span class="current-label"><?php _e( 'Current Theme' ); ?></span>
     454                <# } #>
     455                <h2 class="theme-name">{{{ data.name }}}<span class="theme-version"><?php printf( __( 'Version: %s' ), '{{ data.version }}' ); ?></span></h2>
     456                <p class="theme-author"><?php printf( __( 'By %s' ), '{{{ data.authorAndUri }}}' ); ?></p>
     457
     458                <# if ( data.hasUpdate ) { #>
     459                <div class="notice notice-warning notice-alt notice-large">
     460                    <h3 class="notice-title"><?php _e( 'Update Available' ); ?></h3>
     461                    {{{ data.update }}}
     462                </div>
     463                <# } #>
     464                <p class="theme-description">{{{ data.description }}}</p>
     465
     466                <# if ( data.parent ) { #>
     467                    <p class="parent-theme"><?php printf( __( 'This is a child theme of %s.' ), '<strong>{{{ data.parent }}}</strong>' ); ?></p>
     468                <# } #>
     469
     470                <# if ( data.tags ) { #>
     471                    <p class="theme-tags"><span><?php _e( 'Tags:' ); ?></span> {{{ data.tags }}}</p>
     472                <# } #>
     473            </div>
     474        </div>
     475
     476        <div class="theme-actions">
     477            <div class="active-theme">
     478                <a href="{{{ data.actions.customize }}}" class="button button-primary customize load-customize hide-if-no-customize"><?php _e( 'Customize' ); ?></a>
     479                <?php echo implode( ' ', $current_theme_actions ); ?>
     480            </div>
     481            <div class="inactive-theme">
     482                <?php
     483                /* translators: %s: Theme name */
     484                $aria_label = sprintf( _x( 'Activate %s', 'theme' ), '{{ data.name }}' );
     485                ?>
     486                <# if ( data.actions.activate ) { #>
     487                    <a href="{{{ data.actions.activate }}}" class="button activate" aria-label="<?php echo $aria_label; ?>"><?php _e( 'Activate' ); ?></a>
     488                <# } #>
     489                <a href="{{{ data.actions.customize }}}" class="button button-primary load-customize hide-if-no-customize"><?php _e( 'Live Preview' ); ?></a>
     490            </div>
     491
     492            <# if ( ! data.active && data.actions['delete'] ) { #>
     493                <a href="{{{ data.actions['delete'] }}}" class="button delete-theme"><?php _e( 'Delete' ); ?></a>
     494            <# } #>
     495        </div>
     496    </div>
    495497</script>
    496498
    497499<?php
    wp_print_admin_notice_templates(); 
    500502wp_print_update_row_templates();
    501503
    502504wp_localize_script( 'updates', '_wpUpdatesItemCounts', array(
    503         'totals'  => wp_get_update_data(),
     505    'totals'  => wp_get_update_data(),
    504506) );
    505507
    506508require( ABSPATH . 'wp-admin/admin-footer.php' );
  • src/wp-admin/user-edit.php

    diff --git a/src/wp-admin/user-edit.php b/src/wp-admin/user-edit.php
    index 80cef618e5..d0f4b37840 100644
    a b  
    99/** WordPress Administration Bootstrap */
    1010require_once( dirname( __FILE__ ) . '/admin.php' );
    1111
    12 wp_reset_vars( array( 'action', 'user_id', 'wp_http_referer' ) );
     12$action = wp_assign_request_var('action');
     13$user_id = wp_assign_request_var('user_id');
     14$wp_http_referer = wp_assign_request_var('wp_http_referer');
    1315
    1416$user_id = (int) $user_id;
    1517$current_user = wp_get_current_user();
    1618if ( ! defined( 'IS_PROFILE_PAGE' ) )
    17         define( 'IS_PROFILE_PAGE', ( $user_id == $current_user->ID ) );
     19    define( 'IS_PROFILE_PAGE', ( $user_id == $current_user->ID ) );
    1820
    1921if ( ! $user_id && IS_PROFILE_PAGE )
    20         $user_id = $current_user->ID;
     22    $user_id = $current_user->ID;
    2123elseif ( ! $user_id && ! IS_PROFILE_PAGE )
    22         wp_die(__( 'Invalid user ID.' ) );
     24    wp_die(__( 'Invalid user ID.' ) );
    2325elseif ( ! get_userdata( $user_id ) )
    24         wp_die( __('Invalid user ID.') );
     26    wp_die( __('Invalid user ID.') );
    2527
    2628wp_enqueue_script('user-profile');
    2729
    2830if ( IS_PROFILE_PAGE ) {
    29         $title = __( 'Profile' );
     31    $title = __( 'Profile' );
    3032} else {
    31         /* translators: %s: user's display name */
    32         $title = __( 'Edit User %s' );
     33    /* translators: %s: user's display name */
     34    $title = __( 'Edit User %s' );
    3335}
    3436
    3537if ( current_user_can('edit_users') && !IS_PROFILE_PAGE )
    36         $submenu_file = 'users.php';
     38    $submenu_file = 'users.php';
    3739else
    38         $submenu_file = 'profile.php';
     40    $submenu_file = 'profile.php';
    3941
    4042if ( current_user_can('edit_users') && !is_user_admin() )
    41         $parent_file = 'users.php';
     43    $parent_file = 'users.php';
    4244else
    43         $parent_file = 'profile.php';
     45    $parent_file = 'profile.php';
    4446
    4547$profile_help = '<p>' . __('Your profile contains information about you (your &#8220;account&#8221;) as well as some personal options related to using WordPress.') . '</p>' .
    46         '<p>' . __('You can change your password, turn on keyboard shortcuts, change the color scheme of your WordPress administration screens, and turn off the WYSIWYG (Visual) editor, among other things. You can hide the Toolbar (formerly called the Admin Bar) from the front end of your site, however it cannot be disabled on the admin screens.') . '</p>' .
    47         '<p>' . __( 'You can select the language you wish to use while using the WordPress administration screen without affecting the language site visitors see.' ) . '</p>' .
    48         '<p>' . __('Your username cannot be changed, but you can use other fields to enter your real name or a nickname, and change which name to display on your posts.') . '</p>' .
    49         '<p>' . __( 'You can log out of other devices, such as your phone or a public computer, by clicking the Log Out Everywhere Else button.' ) . '</p>' .
    50         '<p>' . __('Required fields are indicated; the rest are optional. Profile information will only be displayed if your theme is set up to do so.') . '</p>' .
    51         '<p>' . __('Remember to click the Update Profile button when you are finished.') . '</p>';
     48    '<p>' . __('You can change your password, turn on keyboard shortcuts, change the color scheme of your WordPress administration screens, and turn off the WYSIWYG (Visual) editor, among other things. You can hide the Toolbar (formerly called the Admin Bar) from the front end of your site, however it cannot be disabled on the admin screens.') . '</p>' .
     49    '<p>' . __( 'You can select the language you wish to use while using the WordPress administration screen without affecting the language site visitors see.' ) . '</p>' .
     50    '<p>' . __('Your username cannot be changed, but you can use other fields to enter your real name or a nickname, and change which name to display on your posts.') . '</p>' .
     51    '<p>' . __( 'You can log out of other devices, such as your phone or a public computer, by clicking the Log Out Everywhere Else button.' ) . '</p>' .
     52    '<p>' . __('Required fields are indicated; the rest are optional. Profile information will only be displayed if your theme is set up to do so.') . '</p>' .
     53    '<p>' . __('Remember to click the Update Profile button when you are finished.') . '</p>';
    5254
    5355get_current_screen()->add_help_tab( array(
    54         'id'      => 'overview',
    55         'title'   => __('Overview'),
    56         'content' => $profile_help,
     56    'id'      => 'overview',
     57    'title'   => __('Overview'),
     58    'content' => $profile_help,
    5759) );
    5860
    5961get_current_screen()->set_help_sidebar(
    $user_can_edit = current_user_can( 'edit_posts' ) || current_user_can( 'edit_pag 
    8082 * @param bool $allow Whether to allow editing of any user. Default true.
    8183 */
    8284if ( is_multisite()
    83         && ! current_user_can( 'manage_network_users' )
    84         && $user_id != $current_user->ID
    85         && ! apply_filters( 'enable_edit_any_user_configuration', true )
     85    && ! current_user_can( 'manage_network_users' )
     86    && $user_id != $current_user->ID
     87    && ! apply_filters( 'enable_edit_any_user_configuration', true )
    8688) {
    87         wp_die( __( 'Sorry, you are not allowed to edit this user.' ) );
     89    wp_die( __( 'Sorry, you are not allowed to edit this user.' ) );
    8890}
    8991
    9092// Execute confirmed email change. See send_confirmation_on_profile_email().
    9193if ( is_multisite() && IS_PROFILE_PAGE && isset( $_GET[ 'newuseremail' ] ) && $current_user->ID ) {
    92         $new_email = get_user_meta( $current_user->ID, '_new_email', true );
    93         if ( $new_email && hash_equals( $new_email[ 'hash' ], $_GET[ 'newuseremail' ] ) ) {
    94                 $user = new stdClass;
    95                 $user->ID = $current_user->ID;
    96                 $user->user_email = esc_html( trim( $new_email[ 'newemail' ] ) );
    97                 if ( $wpdb->get_var( $wpdb->prepare( "SELECT user_login FROM {$wpdb->signups} WHERE user_login = %s", $current_user->user_login ) ) ) {
    98                         $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->signups} SET user_email = %s WHERE user_login = %s", $user->user_email, $current_user->user_login ) );
    99                 }
    100                 wp_update_user( $user );
    101                 delete_user_meta( $current_user->ID, '_new_email' );
    102                 wp_redirect( add_query_arg( array( 'updated' => 'true' ), self_admin_url( 'profile.php' ) ) );
    103                 die();
    104         } else {
    105                 wp_redirect( add_query_arg( array( 'error' => 'new-email' ), self_admin_url( 'profile.php' ) ) );
    106         }
     94    $new_email = get_user_meta( $current_user->ID, '_new_email', true );
     95    if ( $new_email && hash_equals( $new_email[ 'hash' ], $_GET[ 'newuseremail' ] ) ) {
     96        $user = new stdClass;
     97        $user->ID = $current_user->ID;
     98        $user->user_email = esc_html( trim( $new_email[ 'newemail' ] ) );
     99        if ( $wpdb->get_var( $wpdb->prepare( "SELECT user_login FROM {$wpdb->signups} WHERE user_login = %s", $current_user->user_login ) ) ) {
     100            $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->signups} SET user_email = %s WHERE user_login = %s", $user->user_email, $current_user->user_login ) );
     101        }
     102        wp_update_user( $user );
     103        delete_user_meta( $current_user->ID, '_new_email' );
     104        wp_redirect( add_query_arg( array( 'updated' => 'true' ), self_admin_url( 'profile.php' ) ) );
     105        die();
     106    } else {
     107        wp_redirect( add_query_arg( array( 'error' => 'new-email' ), self_admin_url( 'profile.php' ) ) );
     108    }
    107109} elseif ( is_multisite() && IS_PROFILE_PAGE && !empty( $_GET['dismiss'] ) && $current_user->ID . '_new_email' === $_GET['dismiss'] ) {
    108         check_admin_referer( 'dismiss-' . $current_user->ID . '_new_email' );
    109         delete_user_meta( $current_user->ID, '_new_email' );
    110         wp_redirect( add_query_arg( array('updated' => 'true'), self_admin_url( 'profile.php' ) ) );
    111         die();
     110    check_admin_referer( 'dismiss-' . $current_user->ID . '_new_email' );
     111    delete_user_meta( $current_user->ID, '_new_email' );
     112    wp_redirect( add_query_arg( array('updated' => 'true'), self_admin_url( 'profile.php' ) ) );
     113    die();
    112114}
    113115
    114116switch ($action) {
    case 'update': 
    117119check_admin_referer('update-user_' . $user_id);
    118120
    119121if ( !current_user_can('edit_user', $user_id) )
    120         wp_die(__('Sorry, you are not allowed to edit this user.'));
     122    wp_die(__('Sorry, you are not allowed to edit this user.'));
    121123
    122124if ( IS_PROFILE_PAGE ) {
    123         /**
    124         * Fires before the page loads on the 'Your Profile' editing screen.
    125         *
    126         * The action only fires if the current user is editing their own profile.
    127         *
    128         * @since 2.0.0
    129         *
    130         * @param int $user_id The user ID.
    131         */
    132         do_action( 'personal_options_update', $user_id );
     125    /**
     126    * Fires before the page loads on the 'Your Profile' editing screen.
     127    *
     128    * The action only fires if the current user is editing their own profile.
     129    *
     130    * @since 2.0.0
     131    *
     132    * @param int $user_id The user ID.
     133    */
     134    do_action( 'personal_options_update', $user_id );
    133135} else {
    134         /**
    135         * Fires before the page loads on the 'Edit User' screen.
    136         *
    137         * @since 2.7.0
    138         *
    139         * @param int $user_id The user ID.
    140         */
    141         do_action( 'edit_user_profile_update', $user_id );
     136    /**
     137    * Fires before the page loads on the 'Edit User' screen.
     138    *
     139    * @since 2.7.0
     140    *
     141    * @param int $user_id The user ID.
     142    */
     143    do_action( 'edit_user_profile_update', $user_id );
    142144}
    143145
    144146// Update the email address in signups, if present.
    145147if ( is_multisite() ) {
    146         $user = get_userdata( $user_id );
     148    $user = get_userdata( $user_id );
    147149
    148         if ( $user->user_login && isset( $_POST[ 'email' ] ) && is_email( $_POST[ 'email' ] ) && $wpdb->get_var( $wpdb->prepare( "SELECT user_login FROM {$wpdb->signups} WHERE user_login = %s", $user->user_login ) ) ) {
    149                 $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->signups} SET user_email = %s WHERE user_login = %s", $_POST[ 'email' ], $user_login ) );
    150         }
     150    if ( $user->user_login && isset( $_POST[ 'email' ] ) && is_email( $_POST[ 'email' ] ) && $wpdb->get_var( $wpdb->prepare( "SELECT user_login FROM {$wpdb->signups} WHERE user_login = %s", $user->user_login ) ) ) {
     151        $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->signups} SET user_email = %s WHERE user_login = %s", $_POST[ 'email' ], $user_login ) );
     152    }
    151153}
    152154
    153155// Update the user.
    $errors = edit_user( $user_id ); 
    155157
    156158// Grant or revoke super admin status if requested.
    157159if ( is_multisite() && is_network_admin() && !IS_PROFILE_PAGE && current_user_can( 'manage_network_options' ) && !isset($super_admins) && empty( $_POST['super_admin'] ) == is_super_admin( $user_id ) ) {
    158         empty( $_POST['super_admin'] ) ? revoke_super_admin( $user_id ) : grant_super_admin( $user_id );
     160    empty( $_POST['super_admin'] ) ? revoke_super_admin( $user_id ) : grant_super_admin( $user_id );
    159161}
    160162
    161163if ( !is_wp_error( $errors ) ) {
    162         $redirect = add_query_arg( 'updated', true, get_edit_user_link( $user_id ) );
    163         if ( $wp_http_referer )
    164                 $redirect = add_query_arg('wp_http_referer', urlencode($wp_http_referer), $redirect);
    165         wp_redirect($redirect);
    166         exit;
     164    $redirect = add_query_arg( 'updated', true, get_edit_user_link( $user_id ) );
     165    if ( $wp_http_referer )
     166        $redirect = add_query_arg('wp_http_referer', urlencode($wp_http_referer), $redirect);
     167    wp_redirect($redirect);
     168    exit;
    167169}
    168170
    169171default:
    170172$profileuser = get_user_to_edit($user_id);
    171173
    172174if ( !current_user_can('edit_user', $user_id) )
    173         wp_die(__('Sorry, you are not allowed to edit this user.'));
     175    wp_die(__('Sorry, you are not allowed to edit this user.'));
    174176
    175177$title = sprintf( $title, $profileuser->display_name );
    176178$sessions = WP_Session_Tokens::get_instance( $profileuser->ID );
    include(ABSPATH . 'wp-admin/admin-header.php'); 
    179181?>
    180182
    181183<?php if ( !IS_PROFILE_PAGE && is_super_admin( $profileuser->ID ) && current_user_can( 'manage_network_options' ) ) { ?>
    182         <div class="notice notice-info"><p><strong><?php _e('Important:'); ?></strong> <?php _e('This user has super admin privileges.'); ?></p></div>
     184    <div class="notice notice-info"><p><strong><?php _e('Important:'); ?></strong> <?php _e('This user has super admin privileges.'); ?></p></div>
    183185<?php } ?>
    184186<?php if ( isset($_GET['updated']) ) : ?>
    185187<div id="message" class="updated notice is-dismissible">
    186         <?php if ( IS_PROFILE_PAGE ) : ?>
    187         <p><strong><?php _e('Profile updated.') ?></strong></p>
    188         <?php else: ?>
    189         <p><strong><?php _e('User updated.') ?></strong></p>
    190         <?php endif; ?>
    191         <?php if ( $wp_http_referer && false === strpos( $wp_http_referer, 'user-new.php' ) && ! IS_PROFILE_PAGE ) : ?>
    192         <p><a href="<?php echo esc_url( $wp_http_referer ); ?>"><?php _e('&larr; Back to Users'); ?></a></p>
    193         <?php endif; ?>
     188    <?php if ( IS_PROFILE_PAGE ) : ?>
     189    <p><strong><?php _e('Profile updated.') ?></strong></p>
     190    <?php else: ?>
     191    <p><strong><?php _e('User updated.') ?></strong></p>
     192    <?php endif; ?>
     193    <?php if ( $wp_http_referer && false === strpos( $wp_http_referer, 'user-new.php' ) && ! IS_PROFILE_PAGE ) : ?>
     194    <p><a href="<?php echo esc_url( $wp_http_referer ); ?>"><?php _e('&larr; Back to Users'); ?></a></p>
     195    <?php endif; ?>
    194196</div>
    195197<?php endif; ?>
    196198<?php if ( isset( $_GET['error'] ) ) : ?>
    197199<div class="notice notice-error">
    198         <?php if ( 'new-email' == $_GET['error'] ) : ?>
    199         <p><?php _e( 'Error while saving the new email address. Please try again.' ); ?></p>
    200         <?php endif; ?>
     200    <?php if ( 'new-email' == $_GET['error'] ) : ?>
     201    <p><?php _e( 'Error while saving the new email address. Please try again.' ); ?></p>
     202    <?php endif; ?>
    201203</div>
    202204<?php endif; ?>
    203205<?php if ( isset( $errors ) && is_wp_error( $errors ) ) : ?>
    echo esc_html( $title ); 
    211213
    212214<?php
    213215if ( ! IS_PROFILE_PAGE ) {
    214         if ( current_user_can( 'create_users' ) ) { ?>
    215                 <a href="user-new.php" class="page-title-action"><?php echo esc_html_x( 'Add New', 'user' ); ?></a>
    216         <?php } elseif ( is_multisite() && current_user_can( 'promote_users' ) ) { ?>
    217                 <a href="user-new.php" class="page-title-action"><?php echo esc_html_x( 'Add Existing', 'user' ); ?></a>
    218         <?php }
     216    if ( current_user_can( 'create_users' ) ) { ?>
     217        <a href="user-new.php" class="page-title-action"><?php echo esc_html_x( 'Add New', 'user' ); ?></a>
     218    <?php } elseif ( is_multisite() && current_user_can( 'promote_users' ) ) { ?>
     219        <a href="user-new.php" class="page-title-action"><?php echo esc_html_x( 'Add Existing', 'user' ); ?></a>
     220    <?php }
    219221}
    220222?>
    221223
    222224<hr class="wp-header-end">
    223225
    224226<form id="your-profile" action="<?php echo esc_url( self_admin_url( IS_PROFILE_PAGE ? 'profile.php' : 'user-edit.php' ) ); ?>" method="post" novalidate="novalidate"<?php
    225         /**
    226         * Fires inside the your-profile form tag on the user editing screen.
    227         *
    228         * @since 3.0.0
    229         */
    230         do_action( 'user_edit_form_tag' );
     227    /**
     228    * Fires inside the your-profile form tag on the user editing screen.
     229    *
     230    * @since 3.0.0
     231    */
     232    do_action( 'user_edit_form_tag' );
    231233?>>
    232234<?php wp_nonce_field('update-user_' . $user_id) ?>
    233235<?php if ( $wp_http_referer ) : ?>
    234         <input type="hidden" name="wp_http_referer" value="<?php echo esc_url($wp_http_referer); ?>" />
     236    <input type="hidden" name="wp_http_referer" value="<?php echo esc_url($wp_http_referer); ?>" />
    235237<?php endif; ?>
    236238<p>
    237239<input type="hidden" name="from" value="profile" />
    if ( ! IS_PROFILE_PAGE ) { 
    242244
    243245<table class="form-table">
    244246<?php if ( ! ( IS_PROFILE_PAGE && ! $user_can_edit ) ) : ?>
    245         <tr class="user-rich-editing-wrap">
    246                 <th scope="row"><?php _e( 'Visual Editor' ); ?></th>
    247                 <td><label for="rich_editing"><input name="rich_editing" type="checkbox" id="rich_editing" value="false" <?php if ( ! empty( $profileuser->rich_editing ) ) checked( 'false', $profileuser->rich_editing ); ?> /> <?php _e( 'Disable the visual editor when writing' ); ?></label></td>
    248         </tr>
     247    <tr class="user-rich-editing-wrap">
     248        <th scope="row"><?php _e( 'Visual Editor' ); ?></th>
     249        <td><label for="rich_editing"><input name="rich_editing" type="checkbox" id="rich_editing" value="false" <?php if ( ! empty( $profileuser->rich_editing ) ) checked( 'false', $profileuser->rich_editing ); ?> /> <?php _e( 'Disable the visual editor when writing' ); ?></label></td>
     250    </tr>
    249251<?php endif; ?>
    250252<?php if ( count($_wp_admin_css_colors) > 1 && has_action('admin_color_scheme_picker') ) : ?>
    251253<tr class="user-admin-color-wrap">
    252254<th scope="row"><?php _e('Admin Color Scheme')?></th>
    253255<td><?php
    254         /**
    255         * Fires in the 'Admin Color Scheme' section of the user editing screen.
    256         *
    257         * The section is only enabled if a callback is hooked to the action,
    258         * and if there is more than one defined color scheme for the admin.
    259         *
    260         * @since 3.0.0
    261         * @since 3.8.1 Added `$user_id` parameter.
    262         *
    263         * @param int $user_id The user ID.
    264         */
    265         do_action( 'admin_color_scheme_picker', $user_id );
     256    /**
     257    * Fires in the 'Admin Color Scheme' section of the user editing screen.
     258    *
     259    * The section is only enabled if a callback is hooked to the action,
     260    * and if there is more than one defined color scheme for the admin.
     261    *
     262    * @since 3.0.0
     263    * @since 3.8.1 Added `$user_id` parameter.
     264    *
     265    * @param int $user_id The user ID.
     266    */
     267    do_action( 'admin_color_scheme_picker', $user_id );
    266268?></td>
    267269</tr>
    268270<?php
    if ( !( IS_PROFILE_PAGE && !$user_can_edit ) ) : ?> 
    287289$languages = get_available_languages();
    288290if ( $languages ) : ?>
    289291<tr class="user-language-wrap">
    290         <th scope="row">
    291                 <?php /* translators: The user language selection field label */ ?>
    292                 <label for="locale"><?php _e( 'Language' ); ?></label>
    293         </th>
    294         <td>
    295                 <?php
    296                 $user_locale = $profileuser->locale;
    297 
    298                 if ( 'en_US' === $user_locale ) {
    299                         $user_locale = '';
    300                 } elseif ( '' === $user_locale || ! in_array( $user_locale, $languages, true ) ) {
    301                         $user_locale = 'site-default';
    302                 }
    303 
    304                 wp_dropdown_languages( array(
    305                         'name'                        => 'locale',
    306                         'id'                          => 'locale',
    307                         'selected'                    => $user_locale,
    308                         'languages'                   => $languages,
    309                         'show_available_translations' => false,
    310                         'show_option_site_default'    => true
    311                 ) );
    312                 ?>
    313         </td>
     292    <th scope="row">
     293        <?php /* translators: The user language selection field label */ ?>
     294        <label for="locale"><?php _e( 'Language' ); ?></label>
     295    </th>
     296    <td>
     297        <?php
     298        $user_locale = $profileuser->locale;
     299
     300        if ( 'en_US' === $user_locale ) {
     301            $user_locale = '';
     302        } elseif ( '' === $user_locale || ! in_array( $user_locale, $languages, true ) ) {
     303            $user_locale = 'site-default';
     304        }
     305
     306        wp_dropdown_languages( array(
     307            'name'                        => 'locale',
     308            'id'                          => 'locale',
     309            'selected'                    => $user_locale,
     310            'languages'                   => $languages,
     311            'show_available_translations' => false,
     312            'show_option_site_default'    => true
     313        ) );
     314        ?>
     315    </td>
    314316</tr>
    315317<?php
    316318endif;
    do_action( 'personal_options', $profileuser ); 
    329331
    330332</table>
    331333<?php
    332         if ( IS_PROFILE_PAGE ) {
    333                 /**
    334                 * Fires after the 'Personal Options' settings table on the 'Your Profile' editing screen.
    335                 *
    336                 * The action only fires if the current user is editing their own profile.
    337                 *
    338                 * @since 2.0.0
    339                 *
    340                 * @param WP_User $profileuser The current WP_User object.
    341                 */
    342                 do_action( 'profile_personal_options', $profileuser );
    343         }
     334    if ( IS_PROFILE_PAGE ) {
     335        /**
     336        * Fires after the 'Personal Options' settings table on the 'Your Profile' editing screen.
     337        *
     338        * The action only fires if the current user is editing their own profile.
     339        *
     340        * @since 2.0.0
     341        *
     342        * @param WP_User $profileuser The current WP_User object.
     343        */
     344        do_action( 'profile_personal_options', $profileuser );
     345    }
    344346?>
    345347
    346348<h2><?php _e( 'Name' ); ?></h2>
    347349
    348350<table class="form-table">
    349         <tr class="user-user-login-wrap">
    350                 <th><label for="user_login"><?php _e('Username'); ?></label></th>
    351                 <td><input type="text" name="user_login" id="user_login" value="<?php echo esc_attr($profileuser->user_login); ?>" disabled="disabled" class="regular-text" /> <span class="description"><?php _e('Usernames cannot be changed.'); ?></span></td>
    352         </tr>
     351    <tr class="user-user-login-wrap">
     352        <th><label for="user_login"><?php _e('Username'); ?></label></th>
     353        <td><input type="text" name="user_login" id="user_login" value="<?php echo esc_attr($profileuser->user_login); ?>" disabled="disabled" class="regular-text" /> <span class="description"><?php _e('Usernames cannot be changed.'); ?></span></td>
     354    </tr>
    353355
    354356<?php if ( !IS_PROFILE_PAGE && !is_network_admin() ) : ?>
    355357<tr class="user-role-wrap"><th><label for="role"><?php _e('Role') ?></label></th>
    wp_dropdown_roles($user_role); 
    364366
    365367// print the 'no role' option. Make it selected if the user has no role yet.
    366368if ( $user_role )
    367         echo '<option value="">' . __('&mdash; No role for this site &mdash;') . '</option>';
     369    echo '<option value="">' . __('&mdash; No role for this site &mdash;') . '</option>';
    368370else
    369         echo '<option value="" selected="selected">' . __('&mdash; No role for this site &mdash;') . '</option>';
     371    echo '<option value="" selected="selected">' . __('&mdash; No role for this site &mdash;') . '</option>';
    370372?>
    371373</select></td></tr>
    372374<?php endif; //!IS_PROFILE_PAGE
    if ( is_multisite() && is_network_admin() && ! IS_PROFILE_PAGE && current_user_c 
    383385<?php } ?>
    384386
    385387<tr class="user-first-name-wrap">
    386         <th><label for="first_name"><?php _e('First Name') ?></label></th>
    387         <td><input type="text" name="first_name" id="first_name" value="<?php echo esc_attr($profileuser->first_name) ?>" class="regular-text" /></td>
     388    <th><label for="first_name"><?php _e('First Name') ?></label></th>
     389    <td><input type="text" name="first_name" id="first_name" value="<?php echo esc_attr($profileuser->first_name) ?>" class="regular-text" /></td>
    388390</tr>
    389391
    390392<tr class="user-last-name-wrap">
    391         <th><label for="last_name"><?php _e('Last Name') ?></label></th>
    392         <td><input type="text" name="last_name" id="last_name" value="<?php echo esc_attr($profileuser->last_name) ?>" class="regular-text" /></td>
     393    <th><label for="last_name"><?php _e('Last Name') ?></label></th>
     394    <td><input type="text" name="last_name" id="last_name" value="<?php echo esc_attr($profileuser->last_name) ?>" class="regular-text" /></td>
    393395</tr>
    394396
    395397<tr class="user-nickname-wrap">
    396         <th><label for="nickname"><?php _e('Nickname'); ?> <span class="description"><?php _e('(required)'); ?></span></label></th>
    397         <td><input type="text" name="nickname" id="nickname" value="<?php echo esc_attr($profileuser->nickname) ?>" class="regular-text" /></td>
     398    <th><label for="nickname"><?php _e('Nickname'); ?> <span class="description"><?php _e('(required)'); ?></span></label></th>
     399    <td><input type="text" name="nickname" id="nickname" value="<?php echo esc_attr($profileuser->nickname) ?>" class="regular-text" /></td>
    398400</tr>
    399401
    400402<tr class="user-display-name-wrap">
    401         <th><label for="display_name"><?php _e('Display name publicly as') ?></label></th>
    402         <td>
    403                 <select name="display_name" id="display_name">
    404                 <?php
    405                         $public_display = array();
    406                         $public_display['display_nickname']  = $profileuser->nickname;
    407                         $public_display['display_username']  = $profileuser->user_login;
    408 
    409                         if ( !empty($profileuser->first_name) )
    410                                 $public_display['display_firstname'] = $profileuser->first_name;
    411 
    412                         if ( !empty($profileuser->last_name) )
    413                                 $public_display['display_lastname'] = $profileuser->last_name;
    414 
    415                         if ( !empty($profileuser->first_name) && !empty($profileuser->last_name) ) {
    416                                 $public_display['display_firstlast'] = $profileuser->first_name . ' ' . $profileuser->last_name;
    417                                 $public_display['display_lastfirst'] = $profileuser->last_name . ' ' . $profileuser->first_name;
    418                         }
    419 
    420                         if ( !in_array( $profileuser->display_name, $public_display ) ) // Only add this if it isn't duplicated elsewhere
    421                                 $public_display = array( 'display_displayname' => $profileuser->display_name ) + $public_display;
    422 
    423                         $public_display = array_map( 'trim', $public_display );
    424                         $public_display = array_unique( $public_display );
    425 
    426                         foreach ( $public_display as $id => $item ) {
    427                 ?>
    428                         <option <?php selected( $profileuser->display_name, $item ); ?>><?php echo $item; ?></option>
    429                 <?php
    430                         }
    431                 ?>
    432                 </select>
    433         </td>
     403    <th><label for="display_name"><?php _e('Display name publicly as') ?></label></th>
     404    <td>
     405        <select name="display_name" id="display_name">
     406        <?php
     407            $public_display = array();
     408            $public_display['display_nickname']  = $profileuser->nickname;
     409            $public_display['display_username']  = $profileuser->user_login;
     410
     411            if ( !empty($profileuser->first_name) )
     412                $public_display['display_firstname'] = $profileuser->first_name;
     413
     414            if ( !empty($profileuser->last_name) )
     415                $public_display['display_lastname'] = $profileuser->last_name;
     416
     417            if ( !empty($profileuser->first_name) && !empty($profileuser->last_name) ) {
     418                $public_display['display_firstlast'] = $profileuser->first_name . ' ' . $profileuser->last_name;
     419                $public_display['display_lastfirst'] = $profileuser->last_name . ' ' . $profileuser->first_name;
     420            }
     421
     422            if ( !in_array( $profileuser->display_name, $public_display ) ) // Only add this if it isn't duplicated elsewhere
     423                $public_display = array( 'display_displayname' => $profileuser->display_name ) + $public_display;
     424
     425            $public_display = array_map( 'trim', $public_display );
     426            $public_display = array_unique( $public_display );
     427
     428            foreach ( $public_display as $id => $item ) {
     429        ?>
     430            <option <?php selected( $profileuser->display_name, $item ); ?>><?php echo $item; ?></option>
     431        <?php
     432            }
     433        ?>
     434        </select>
     435    </td>
    434436</tr>
    435437</table>
    436438
    if ( is_multisite() && is_network_admin() && ! IS_PROFILE_PAGE && current_user_c 
    438440
    439441<table class="form-table">
    440442<tr class="user-email-wrap">
    441         <th><label for="email"><?php _e('Email'); ?> <span class="description"><?php _e('(required)'); ?></span></label></th>
    442         <td><input type="email" name="email" id="email" value="<?php echo esc_attr( $profileuser->user_email ) ?>" class="regular-text ltr" />
    443         <?php
    444         $new_email = get_user_meta( $current_user->ID, '_new_email', true );
    445         if ( $new_email && $new_email['newemail'] != $current_user->user_email && $profileuser->ID == $current_user->ID ) : ?>
    446         <div class="updated inline">
    447         <p><?php
    448                 printf(
    449                         /* translators: %s: new email */
    450                         __( 'There is a pending change of your email to %s.' ),
    451                         '<code>' . esc_html( $new_email['newemail'] ) . '</code>'
    452                 );
    453                 printf(
    454                         ' <a href="%1$s">%2$s</a>',
    455                         esc_url( wp_nonce_url( self_admin_url( 'profile.php?dismiss=' . $current_user->ID . '_new_email' ), 'dismiss-' . $current_user->ID . '_new_email' ) ),
    456                         __( 'Cancel' )
    457                 );
    458         ?></p>
    459         </div>
    460         <?php endif; ?>
    461         </td>
     443    <th><label for="email"><?php _e('Email'); ?> <span class="description"><?php _e('(required)'); ?></span></label></th>
     444    <td><input type="email" name="email" id="email" value="<?php echo esc_attr( $profileuser->user_email ) ?>" class="regular-text ltr" />
     445    <?php
     446    $new_email = get_user_meta( $current_user->ID, '_new_email', true );
     447    if ( $new_email && $new_email['newemail'] != $current_user->user_email && $profileuser->ID == $current_user->ID ) : ?>
     448    <div class="updated inline">
     449    <p><?php
     450        printf(
     451            /* translators: %s: new email */
     452            __( 'There is a pending change of your email to %s.' ),
     453            '<code>' . esc_html( $new_email['newemail'] ) . '</code>'
     454        );
     455        printf(
     456            ' <a href="%1$s">%2$s</a>',
     457            esc_url( wp_nonce_url( self_admin_url( 'profile.php?dismiss=' . $current_user->ID . '_new_email' ), 'dismiss-' . $current_user->ID . '_new_email' ) ),
     458            __( 'Cancel' )
     459        );
     460    ?></p>
     461    </div>
     462    <?php endif; ?>
     463    </td>
    462464</tr>
    463465
    464466<tr class="user-url-wrap">
    465         <th><label for="url"><?php _e('Website') ?></label></th>
    466         <td><input type="url" name="url" id="url" value="<?php echo esc_attr( $profileuser->user_url ) ?>" class="regular-text code" /></td>
     467    <th><label for="url"><?php _e('Website') ?></label></th>
     468    <td><input type="url" name="url" id="url" value="<?php echo esc_attr( $profileuser->user_url ) ?>" class="regular-text code" /></td>
    467469</tr>
    468470
    469471<?php
    470         foreach ( wp_get_user_contact_methods( $profileuser ) as $name => $desc ) {
     472    foreach ( wp_get_user_contact_methods( $profileuser ) as $name => $desc ) {
    471473?>
    472474<tr class="user-<?php echo $name; ?>-wrap">
    473         <th><label for="<?php echo $name; ?>">
    474                 <?php
    475                 /**
    476                 * Filters a user contactmethod label.
    477                 *
    478                 * The dynamic portion of the filter hook, `$name`, refers to
    479                 * each of the keys in the contactmethods array.
    480                 *
    481                 * @since 2.9.0
    482                 *
    483                 * @param string $desc The translatable label for the contactmethod.
    484                 */
    485                 echo apply_filters( "user_{$name}_label", $desc );
    486                 ?>
    487         </label></th>
    488         <td><input type="text" name="<?php echo $name; ?>" id="<?php echo $name; ?>" value="<?php echo esc_attr($profileuser->$name) ?>" class="regular-text" /></td>
     475    <th><label for="<?php echo $name; ?>">
     476        <?php
     477        /**
     478        * Filters a user contactmethod label.
     479        *
     480        * The dynamic portion of the filter hook, `$name`, refers to
     481        * each of the keys in the contactmethods array.
     482        *
     483        * @since 2.9.0
     484        *
     485        * @param string $desc The translatable label for the contactmethod.
     486        */
     487        echo apply_filters( "user_{$name}_label", $desc );
     488        ?>
     489    </label></th>
     490    <td><input type="text" name="<?php echo $name; ?>" id="<?php echo $name; ?>" value="<?php echo esc_attr($profileuser->$name) ?>" class="regular-text" /></td>
    489491</tr>
    490492<?php
    491         }
     493    }
    492494?>
    493495</table>
    494496
    if ( is_multisite() && is_network_admin() && ! IS_PROFILE_PAGE && current_user_c 
    496498
    497499<table class="form-table">
    498500<tr class="user-description-wrap">
    499         <th><label for="description"><?php _e('Biographical Info'); ?></label></th>
    500         <td><textarea name="description" id="description" rows="5" cols="30"><?php echo $profileuser->description; // textarea_escaped ?></textarea>
    501         <p class="description"><?php _e('Share a little biographical information to fill out your profile. This may be shown publicly.'); ?></p></td>
     501    <th><label for="description"><?php _e('Biographical Info'); ?></label></th>
     502    <td><textarea name="description" id="description" rows="5" cols="30"><?php echo $profileuser->description; // textarea_escaped ?></textarea>
     503    <p class="description"><?php _e('Share a little biographical information to fill out your profile. This may be shown publicly.'); ?></p></td>
    502504</tr>
    503505
    504506<?php if ( get_option( 'show_avatars' ) ) : ?>
    505507<tr class="user-profile-picture">
    506         <th><?php _e( 'Profile Picture' ); ?></th>
    507         <td>
    508                 <?php echo get_avatar( $user_id ); ?>
    509                 <p class="description"><?php
    510                         if ( IS_PROFILE_PAGE ) {
    511                                 /* translators: %s: Gravatar URL */
    512                                 $description = sprintf( __( 'You can change your profile picture on <a href="%s">Gravatar</a>.' ),
    513                                         __( 'https://en.gravatar.com/' )
    514                                 );
    515                         } else {
    516                                 $description = '';
    517                         }
    518 
    519                         /**
    520                         * Filters the user profile picture description displayed under the Gravatar.
    521                         *
    522                         * @since 4.4.0
    523                         * @since 4.7.0 Added the `$profileuser` parameter.
    524                         *
    525                         * @param string  $description The description that will be printed.
    526                         * @param WP_User $profileuser The current WP_User object.
    527                         */
    528                         echo apply_filters( 'user_profile_picture_description', $description, $profileuser );
    529                 ?></p>
    530         </td>
     508    <th><?php _e( 'Profile Picture' ); ?></th>
     509    <td>
     510        <?php echo get_avatar( $user_id ); ?>
     511        <p class="description"><?php
     512            if ( IS_PROFILE_PAGE ) {
     513                /* translators: %s: Gravatar URL */
     514                $description = sprintf( __( 'You can change your profile picture on <a href="%s">Gravatar</a>.' ),
     515                    __( 'https://en.gravatar.com/' )
     516                );
     517            } else {
     518                $description = '';
     519            }
     520
     521            /**
     522            * Filters the user profile picture description displayed under the Gravatar.
     523            *
     524            * @since 4.4.0
     525            * @since 4.7.0 Added the `$profileuser` parameter.
     526            *
     527            * @param string  $description The description that will be printed.
     528            * @param WP_User $profileuser The current WP_User object.
     529            */
     530            echo apply_filters( 'user_profile_picture_description', $description, $profileuser );
     531        ?></p>
     532    </td>
    531533</tr>
    532534<?php endif; ?>
    533535
    if ( $show_password_fields = apply_filters( 'show_password_fields', true, $profi 
    549551<h2><?php _e( 'Account Management' ); ?></h2>
    550552<table class="form-table">
    551553<tr id="password" class="user-pass1-wrap">
    552         <th><label for="pass1"><?php _e( 'New Password' ); ?></label></th>
    553         <td>
    554                 <input class="hidden" value=" " /><!-- #24364 workaround -->
    555                 <button type="button" class="button wp-generate-pw hide-if-no-js"><?php _e( 'Generate Password' ); ?></button>
    556                 <div class="wp-pwd hide-if-js">
    557                         <span class="password-input-wrapper">
    558                                 <input type="password" name="pass1" id="pass1" class="regular-text" value="" autocomplete="off" data-pw="<?php echo esc_attr( wp_generate_password( 24 ) ); ?>" aria-describedby="pass-strength-result" />
    559                         </span>
    560                         <button type="button" class="button wp-hide-pw hide-if-no-js" data-toggle="0" aria-label="<?php esc_attr_e( 'Hide password' ); ?>">
    561                                 <span class="dashicons dashicons-hidden"></span>
    562                                 <span class="text"><?php _e( 'Hide' ); ?></span>
    563                         </button>
    564                         <button type="button" class="button wp-cancel-pw hide-if-no-js" data-toggle="0" aria-label="<?php esc_attr_e( 'Cancel password change' ); ?>">
    565                                 <span class="text"><?php _e( 'Cancel' ); ?></span>
    566                         </button>
    567                         <div style="display:none" id="pass-strength-result" aria-live="polite"></div>
    568                 </div>
    569         </td>
     554    <th><label for="pass1"><?php _e( 'New Password' ); ?></label></th>
     555    <td>
     556        <input class="hidden" value=" " /><!-- #24364 workaround -->
     557        <button type="button" class="button wp-generate-pw hide-if-no-js"><?php _e( 'Generate Password' ); ?></button>
     558        <div class="wp-pwd hide-if-js">
     559            <span class="password-input-wrapper">
     560                <input type="password" name="pass1" id="pass1" class="regular-text" value="" autocomplete="off" data-pw="<?php echo esc_attr( wp_generate_password( 24 ) ); ?>" aria-describedby="pass-strength-result" />
     561            </span>
     562            <button type="button" class="button wp-hide-pw hide-if-no-js" data-toggle="0" aria-label="<?php esc_attr_e( 'Hide password' ); ?>">
     563                <span class="dashicons dashicons-hidden"></span>
     564                <span class="text"><?php _e( 'Hide' ); ?></span>
     565            </button>
     566            <button type="button" class="button wp-cancel-pw hide-if-no-js" data-toggle="0" aria-label="<?php esc_attr_e( 'Cancel password change' ); ?>">
     567                <span class="text"><?php _e( 'Cancel' ); ?></span>
     568            </button>
     569            <div style="display:none" id="pass-strength-result" aria-live="polite"></div>
     570        </div>
     571    </td>
    570572</tr>
    571573<tr class="user-pass2-wrap hide-if-js">
    572         <th scope="row"><label for="pass2"><?php _e( 'Repeat New Password' ); ?></label></th>
    573         <td>
    574         <input name="pass2" type="password" id="pass2" class="regular-text" value="" autocomplete="off" />
    575         <p class="description"><?php _e( 'Type your new password again.' ); ?></p>
    576         </td>
     574    <th scope="row"><label for="pass2"><?php _e( 'Repeat New Password' ); ?></label></th>
     575    <td>
     576    <input name="pass2" type="password" id="pass2" class="regular-text" value="" autocomplete="off" />
     577    <p class="description"><?php _e( 'Type your new password again.' ); ?></p>
     578    </td>
    577579</tr>
    578580<tr class="pw-weak">
    579         <th><?php _e( 'Confirm Password' ); ?></th>
    580         <td>
    581                 <label>
    582                         <input type="checkbox" name="pw_weak" class="pw-checkbox" />
    583                         <span id="pw-weak-text-label"><?php _e( 'Confirm use of potentially weak password' ); ?></span>
    584                 </label>
    585         </td>
     581    <th><?php _e( 'Confirm Password' ); ?></th>
     582    <td>
     583        <label>
     584            <input type="checkbox" name="pw_weak" class="pw-checkbox" />
     585            <span id="pw-weak-text-label"><?php _e( 'Confirm use of potentially weak password' ); ?></span>
     586        </label>
     587    </td>
    586588</tr>
    587589<?php endif; ?>
    588590
    589591<?php
    590592if ( IS_PROFILE_PAGE && count( $sessions->get_all() ) === 1 ) : ?>
    591         <tr class="user-sessions-wrap hide-if-no-js">
    592                 <th><?php _e( 'Sessions' ); ?></th>
    593                 <td aria-live="assertive">
    594                         <div class="destroy-sessions"><button type="button" disabled class="button"><?php _e( 'Log Out Everywhere Else' ); ?></button></div>
    595                         <p class="description">
    596                                 <?php _e( 'You are only logged in at this location.' ); ?>
    597                         </p>
    598                 </td>
    599         </tr>
     593    <tr class="user-sessions-wrap hide-if-no-js">
     594        <th><?php _e( 'Sessions' ); ?></th>
     595        <td aria-live="assertive">
     596            <div class="destroy-sessions"><button type="button" disabled class="button"><?php _e( 'Log Out Everywhere Else' ); ?></button></div>
     597            <p class="description">
     598                <?php _e( 'You are only logged in at this location.' ); ?>
     599            </p>
     600        </td>
     601    </tr>
    600602<?php elseif ( IS_PROFILE_PAGE && count( $sessions->get_all() ) > 1 ) : ?>
    601         <tr class="user-sessions-wrap hide-if-no-js">
    602                 <th><?php _e( 'Sessions' ); ?></th>
    603                 <td aria-live="assertive">
    604                         <div class="destroy-sessions"><button type="button" class="button" id="destroy-sessions"><?php _e( 'Log Out Everywhere Else' ); ?></button></div>
    605                         <p class="description">
    606                                 <?php _e( 'Did you lose your phone or leave your account logged in at a public computer? You can log out everywhere else, and stay logged in here.' ); ?>
    607                         </p>
    608                 </td>
    609         </tr>
     603    <tr class="user-sessions-wrap hide-if-no-js">
     604        <th><?php _e( 'Sessions' ); ?></th>
     605        <td aria-live="assertive">
     606            <div class="destroy-sessions"><button type="button" class="button" id="destroy-sessions"><?php _e( 'Log Out Everywhere Else' ); ?></button></div>
     607            <p class="description">
     608                <?php _e( 'Did you lose your phone or leave your account logged in at a public computer? You can log out everywhere else, and stay logged in here.' ); ?>
     609            </p>
     610        </td>
     611    </tr>
    610612<?php elseif ( ! IS_PROFILE_PAGE && $sessions->get_all() ) : ?>
    611         <tr class="user-sessions-wrap hide-if-no-js">
    612                 <th><?php _e( 'Sessions' ); ?></th>
    613                 <td>
    614                         <p><button type="button" class="button" id="destroy-sessions"><?php _e( 'Log Out Everywhere' ); ?></button></p>
    615                         <p class="description">
    616                                 <?php
    617                                 /* translators: 1: User's display name. */
    618                                 printf( __( 'Log %s out of all locations.' ), $profileuser->display_name );
    619                                 ?>
    620                         </p>
    621                 </td>
    622         </tr>
     613    <tr class="user-sessions-wrap hide-if-no-js">
     614        <th><?php _e( 'Sessions' ); ?></th>
     615        <td>
     616            <p><button type="button" class="button" id="destroy-sessions"><?php _e( 'Log Out Everywhere' ); ?></button></p>
     617            <p class="description">
     618                <?php
     619                /* translators: 1: User's display name. */
     620                printf( __( 'Log %s out of all locations.' ), $profileuser->display_name );
     621                ?>
     622            </p>
     623        </td>
     624    </tr>
    623625<?php endif; ?>
    624626
    625627</table>
    626628
    627629<?php
    628         if ( IS_PROFILE_PAGE ) {
    629                 /**
    630                 * Fires after the 'About Yourself' settings table on the 'Your Profile' editing screen.
    631                 *
    632                 * The action only fires if the current user is editing their own profile.
    633                 *
    634                 * @since 2.0.0
    635                 *
    636                 * @param WP_User $profileuser The current WP_User object.
    637                 */
    638                 do_action( 'show_user_profile', $profileuser );
    639         } else {
    640                 /**
    641                 * Fires after the 'About the User' settings table on the 'Edit User' screen.
    642                 *
    643                 * @since 2.0.0
    644                 *
    645                 * @param WP_User $profileuser The current WP_User object.
    646                 */
    647                 do_action( 'edit_user_profile', $profileuser );
    648         }
     630    if ( IS_PROFILE_PAGE ) {
     631        /**
     632        * Fires after the 'About Yourself' settings table on the 'Your Profile' editing screen.
     633        *
     634        * The action only fires if the current user is editing their own profile.
     635        *
     636        * @since 2.0.0
     637        *
     638        * @param WP_User $profileuser The current WP_User object.
     639        */
     640        do_action( 'show_user_profile', $profileuser );
     641    } else {
     642        /**
     643        * Fires after the 'About the User' settings table on the 'Edit User' screen.
     644        *
     645        * @since 2.0.0
     646        *
     647        * @param WP_User $profileuser The current WP_User object.
     648        */
     649        do_action( 'edit_user_profile', $profileuser );
     650    }
    649651?>
    650652
    651653<?php
    if ( IS_PROFILE_PAGE && count( $sessions->get_all() ) === 1 ) : ?> 
    662664 * @param WP_User $profileuser The current WP_User object.
    663665 */
    664666if ( count( $profileuser->caps ) > count( $profileuser->roles )
    665         && apply_filters( 'additional_capabilities_display', true, $profileuser )
     667    && apply_filters( 'additional_capabilities_display', true, $profileuser )
    666668) : ?>
    667669<h2><?php _e( 'Additional Capabilities' ); ?></h2>
    668670<table class="form-table">
    669671<tr class="user-capabilities-wrap">
    670         <th scope="row"><?php _e( 'Capabilities' ); ?></th>
    671         <td>
     672    <th scope="row"><?php _e( 'Capabilities' ); ?></th>
     673    <td>
    672674<?php
    673         $output = '';
    674         foreach ( $profileuser->caps as $cap => $value ) {
    675                 if ( ! $wp_roles->is_role( $cap ) ) {
    676                         if ( '' != $output )
    677                                 $output .= ', ';
    678                         $output .= $value ? $cap : sprintf( __( 'Denied: %s' ), $cap );
    679                 }
    680         }
    681         echo $output;
     675    $output = '';
     676    foreach ( $profileuser->caps as $cap => $value ) {
     677        if ( ! $wp_roles->is_role( $cap ) ) {
     678            if ( '' != $output )
     679                $output .= ', ';
     680            $output .= $value ? $cap : sprintf( __( 'Denied: %s' ), $cap );
     681        }
     682    }
     683    echo $output;
    682684?>
    683         </td>
     685    </td>
    684686</tr>
    685687</table>
    686688<?php endif; ?>
    break; 
    697699}
    698700?>
    699701<script type="text/javascript">
    700         if (window.location.hash == '#password') {
    701                 document.getElementById('pass1').focus();
    702         }
     702    if (window.location.hash == '#password') {
     703        document.getElementById('pass1').focus();
     704    }
    703705</script>
    704706<?php
    705707include( ABSPATH . 'wp-admin/admin-footer.php');