Make WordPress Core


Ignore:
Timestamp:
05/20/2020 06:47:24 PM (6 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.