Make WordPress Core


Ignore:
Timestamp:
05/20/2020 06:47:24 PM (4 years ago)
Author:
whyisjake
Message:

Security: Add user interface to auto-update themes and plugins.

Building on core update mechanisms, this adds the ability to enable automatic updates for themes and plugins to the WordPress admin.

Fixes: #50052.
Props: afercia, afragen, audrasjb, azaozz, bookdude13, davidperonne, desrosj, gmays, gmays, javiercasares, karmatosed, knutsp, mapk, mukesh27, netweb, nicolaskulka, nielsdeblaauw, paaljoachim, passoniate, pbiron, pedromendonca, whodunitagency, whyisjake, wpamitkumar, and xkon.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/plugins.php

    r47808 r47835  
    2323
    2424// Clean up request URI from temporary args for screen options/paging uri's to work as expected.
    25 $_SERVER['REQUEST_URI'] = remove_query_arg( array( 'error', 'deleted', 'activate', 'activate-multi', 'deactivate', 'deactivate-multi', '_error_nonce' ), $_SERVER['REQUEST_URI'] );
     25$query_args_to_remove = array(
     26    'error',
     27    'deleted',
     28    'activate',
     29    'activate-multi',
     30    'deactivate',
     31    'deactivate-multi',
     32    'enabled-auto-update',
     33    'disabled-auto-update',
     34    'enabled-auto-update-multi',
     35    'disabled-auto-update-multi',
     36    '_error_nonce',
     37);
     38
     39$_SERVER['REQUEST_URI'] = remove_query_arg( $query_args_to_remove, $_SERVER['REQUEST_URI'] );
    2640
    2741wp_enqueue_script( 'updates' );
     
    285299                wp_enqueue_script( 'jquery' );
    286300                require_once ABSPATH . 'wp-admin/admin-header.php';
     301
    287302                ?>
    288             <div class="wrap">
     303                <div class="wrap">
    289304                <?php
    290                     $plugin_info              = array();
    291                     $have_non_network_plugins = false;
     305
     306                $plugin_info              = array();
     307                $have_non_network_plugins = false;
     308
    292309                foreach ( (array) $plugins as $plugin ) {
    293310                    $plugin_slug = dirname( $plugin );
     
    316333                    }
    317334                }
    318                     $plugins_to_delete = count( $plugin_info );
     335
     336                $plugins_to_delete = count( $plugin_info );
     337
    319338                ?>
    320                 <?php if ( 1 == $plugins_to_delete ) : ?>
     339                <?php if ( 1 === $plugins_to_delete ) : ?>
    321340                    <h1><?php _e( 'Delete Plugin' ); ?></h1>
    322341                    <?php if ( $have_non_network_plugins && is_network_admin() ) : ?>
     
    333352                    <ul class="ul-disc">
    334353                        <?php
     354
    335355                        $data_to_delete = false;
     356
    336357                        foreach ( $plugin_info as $plugin ) {
    337358                            if ( $plugin['is_uninstallable'] ) {
     
    344365                            }
    345366                        }
     367
    346368                        ?>
    347369                    </ul>
    348370                <p>
    349371                <?php
     372
    350373                if ( $data_to_delete ) {
    351374                    _e( 'Are you sure you want to delete these files and data?' );
     
    353376                    _e( 'Are you sure you want to delete these files?' );
    354377                }
     378
    355379                ?>
    356380                </p>
     
    359383                    <input type="hidden" name="action" value="delete-selected" />
    360384                    <?php
     385
    361386                    foreach ( (array) $plugins as $plugin ) {
    362387                        echo '<input type="hidden" name="checked[]" value="' . esc_attr( $plugin ) . '" />';
    363388                    }
     389
    364390                    ?>
    365391                    <?php wp_nonce_field( 'bulk-plugins' ); ?>
     
    367393                </form>
    368394                <?php
     395
    369396                $referer = wp_get_referer();
     397
    370398                ?>
    371399                <form method="post" action="<?php echo $referer ? esc_url( $referer ) : ''; ?>" style="display:inline;">
    372400                    <?php submit_button( __( 'No, return me to the plugin list' ), '', 'submit', false ); ?>
    373401                </form>
    374             </div>
     402                </div>
    375403                <?php
     404
    376405                require_once ABSPATH . 'wp-admin/admin-footer.php';
    377406                exit;
     
    386415            wp_redirect( self_admin_url( "plugins.php?deleted=$plugins_to_delete&plugin_status=$status&paged=$page&s=$s" ) );
    387416            exit;
    388 
    389417        case 'clear-recent-list':
    390418            if ( ! is_network_admin() ) {
     
    393421                update_site_option( 'recently_activated', array() );
    394422            }
     423
    395424            break;
    396 
    397425        case 'resume':
    398426            if ( is_multisite() ) {
     
    414442            wp_redirect( self_admin_url( "plugins.php?resume=true&plugin_status=$status&paged=$page&s=$s" ) );
    415443            exit;
    416 
     444        case 'enable-auto-update':
     445        case 'disable-auto-update':
     446        case 'enable-auto-update-selected':
     447        case 'disable-auto-update-selected':
     448            if ( ! current_user_can( 'update_plugins' ) || ! wp_is_auto_update_enabled_for_type( 'plugin' ) ) {
     449                wp_die( __( 'Sorry, you are not allowed to manage plugins automatic updates.' ) );
     450            }
     451
     452            if ( is_multisite() && ! is_network_admin() ) {
     453                wp_die( __( 'Please connect to your network admin to manage plugins automatic updates.' ) );
     454            }
     455
     456            $redirect = self_admin_url( "plugins.php?plugin_status={$status}&paged={$page}&s={$s}" );
     457
     458            if ( 'enable-auto-update' === $action || 'disable-auto-update' === $action ) {
     459                if ( empty( $plugin ) ) {
     460                    wp_redirect( $redirect );
     461                    exit;
     462                }
     463
     464                check_admin_referer( 'updates' );
     465            } else {
     466                if ( empty( $_POST['checked'] ) ) {
     467                    wp_redirect( $redirect );
     468                    exit;
     469                }
     470
     471                check_admin_referer( 'bulk-plugins' );
     472            }
     473
     474            $auto_updates = (array) get_site_option( 'auto_update_plugins', array() );
     475
     476            if ( 'enable-auto-update' === $action ) {
     477                $auto_updates[] = $plugin;
     478                $auto_updates   = array_unique( $auto_updates );
     479                $redirect       = add_query_arg( array( 'enabled-auto-update' => 'true' ), $redirect );
     480            } elseif ( 'disable-auto-update' === $action ) {
     481                $auto_updates = array_diff( $auto_updates, array( $plugin ) );
     482                $redirect     = add_query_arg( array( 'disabled-auto-update' => 'true' ), $redirect );
     483            } else {
     484                $plugins = (array) wp_unslash( $_POST['checked'] );
     485
     486                if ( 'enable-auto-update-selected' === $action ) {
     487                    $new_auto_updates = array_merge( $auto_updates, $plugins );
     488                    $new_auto_updates = array_unique( $new_auto_updates );
     489                    $query_args       = array( 'enabled-auto-update-multi' => 'true' );
     490                } else {
     491                    $new_auto_updates = array_diff( $auto_updates, $plugins );
     492                    $query_args       = array( 'disabled-auto-update-multi' => 'true' );
     493                }
     494
     495                // Return early if all selected plugins already have auto-updates enabled or disabled.
     496                // Must use non-strict comparison, so that array order is not treated as significant.
     497                if ( $new_auto_updates == $auto_updates ) { // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
     498                    wp_redirect( $redirect );
     499                    exit;
     500                }
     501
     502                $auto_updates = $new_auto_updates;
     503                $redirect     = add_query_arg( $query_args, $redirect );
     504            }
     505
     506            /** This filter is documented in wp-admin/includes/class-wp-plugins-list-table.php */
     507            $all_items = apply_filters( 'all_plugins', get_plugins() );
     508
     509            // Remove plugins that don't exist or have been deleted since the option was last updated.
     510            $auto_updates = array_intersect( $auto_updates, array_keys( $all_items ) );
     511
     512            update_site_option( 'auto_update_plugins', $auto_updates );
     513
     514            wp_redirect( $redirect );
     515            exit;
    417516        default:
    418517            if ( isset( $_POST['checked'] ) ) {
     
    499598    }
    500599}
    501 ?>
    502 
    503 <?php
     600
    504601if ( isset( $_GET['error'] ) ) :
    505602
     
    522619        $errmsg = __( 'Plugin could not be activated because it triggered a <strong>fatal error</strong>.' );
    523620    }
     621
    524622    ?>
    525623    <div id="message" class="error"><p><?php echo $errmsg; ?></p>
    526624    <?php
     625
    527626    if ( ! isset( $_GET['main'] ) && ! isset( $_GET['charsout'] ) && wp_verify_nonce( $_GET['_error_nonce'], 'plugin-activation-error_' . $plugin ) ) {
    528627        $iframe_url = add_query_arg(
     
    534633            admin_url( 'plugins.php' )
    535634        );
     635
    536636        ?>
    537     <iframe style="border:0" width="100%" height="70px" src="<?php echo esc_url( $iframe_url ); ?>"></iframe>
     637        <iframe style="border:0" width="100%" height="70px" src="<?php echo esc_url( $iframe_url ); ?>"></iframe>
    538638        <?php
    539639    }
     640
    540641    ?>
    541642    </div>
    542643    <?php
    543644elseif ( isset( $_GET['deleted'] ) ) :
    544         $delete_result = get_transient( 'plugins_delete_result_' . $user_ID );
    545         // Delete it once we're done.
    546         delete_transient( 'plugins_delete_result_' . $user_ID );
     645    $delete_result = get_transient( 'plugins_delete_result_' . $user_ID );
     646    // Delete it once we're done.
     647    delete_transient( 'plugins_delete_result_' . $user_ID );
    547648
    548649    if ( is_wp_error( $delete_result ) ) :
     
    563664            <p>
    564665                <?php
    565                 if ( 1 == (int) $_GET['deleted'] ) {
     666                if ( 1 === (int) $_GET['deleted'] ) {
    566667                    _e( 'The selected plugin has been deleted.' );
    567668                } else {
     
    571672            </p>
    572673        </div>
    573         <?php endif; ?>
     674    <?php endif; ?>
    574675<?php elseif ( isset( $_GET['activate'] ) ) : ?>
    575676    <div id="message" class="updated notice is-dismissible"><p><?php _e( 'Plugin activated.' ); ?></p></div>
     
    584685<?php elseif ( isset( $_GET['resume'] ) ) : ?>
    585686    <div id="message" class="updated notice is-dismissible"><p><?php _e( 'Plugin resumed.' ); ?></p></div>
     687<?php elseif ( isset( $_GET['enabled-auto-update'] ) ) : ?>
     688    <div id="message" class="updated notice is-dismissible"><p><?php _e( 'Plugin will be auto-updated.' ); ?></p></div>
     689<?php elseif ( isset( $_GET['disabled-auto-update'] ) ) : ?>
     690    <div id="message" class="updated notice is-dismissible"><p><?php _e( 'Plugin will no longer be auto-updated.' ); ?></p></div>
     691<?php elseif ( isset( $_GET['enabled-auto-update-multi'] ) ) : ?>
     692    <div id="message" class="updated notice is-dismissible"><p><?php _e( 'Selected plugins will be auto-updated.' ); ?></p></div>
     693<?php elseif ( isset( $_GET['disabled-auto-update-multi'] ) ) : ?>
     694    <div id="message" class="updated notice is-dismissible"><p><?php _e( 'Selected plugins will no longer be auto-updated.' ); ?></p></div>
    586695<?php endif; ?>
    587696
Note: See TracChangeset for help on using the changeset viewer.