Make WordPress Core

Changeset 31811


Ignore:
Timestamp:
03/18/2015 03:17:59 AM (9 years ago)
Author:
jorbin
Message:

Request FTP and SSH credentials when needed during shiny updates

This is a restoration of [31749] which was reverted in [31755].

It includes a number of enhancements from the original version. Namely:

  • Not doing a credential check in src/wp-includes/script-loader.php
  • Add new function wp_print_request_filesystem_credentials_modal
  • update the version number in the list table when a plugin is updated

UI still needs further work, but this basic version should enable more testing

Props ericlewis, jorbin
See #31528

Location:
trunk/src/wp-admin
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/css/forms.css

    r31806 r31811  
    849849}
    850850
     851/*------------------------------------------------------------------------------
     852   Credentials check dialog for Install and Updates
     853------------------------------------------------------------------------------*/
     854
     855.request-filesystem-credentials-dialog {
     856    display: none;
     857}
     858
     859.request-filesystem-credentials-dialog .notification-dialog {
     860    top: 15%;
     861}
     862
     863.request-filesystem-credentials-dialog-content {
     864    margin: 25px;
     865}
     866
     867.request-filesystem-credentials-dialog-content input[type="text"],
     868.request-filesystem-credentials-dialog-content input[type="password"] {
     869    width: 85%;
     870}
     871
    851872/* =Media Queries
    852873-------------------------------------------------------------- */
  • trunk/src/wp-admin/includes/ajax-actions.php

    r31755 r31811  
    29142914        $status['error'] = $result->get_error_message();
    29152915        wp_send_json_error( $status );
     2916    } else if ( is_null( $result ) ) {
     2917        $status['errorCode'] = 'unable_to_connect_to_filesystem';
     2918        $status['error'] = __( 'Unable to connect to the filesystem. Please confirm your credentials.' );
     2919        wp_send_json_error( $status );
    29162920    }
    29172921
     
    29342938
    29352939    $status = array(
    2936         'update' => 'plugin',
    2937         'plugin' => $plugin,
    2938         'slug'   => sanitize_key( $_POST['slug'] ),
     2940        'update'     => 'plugin',
     2941        'plugin'     => $plugin,
     2942        'slug'       => sanitize_key( $_POST['slug'] ),
     2943        'oldVersion' => '',
     2944        'newVersion' => '',
    29392945    );
     2946    $plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
     2947    if ( $plugin_data['Version'] ) {
     2948        $status['oldVersion'] = sprintf( __( 'Version %s' ), $plugin_data['Version'] );
     2949    }
    29402950
    29412951    if ( ! current_user_can( 'update_plugins' ) ) {
     
    29572967
    29582968    if ( is_array( $result ) ) {
    2959         $result = $result[ $plugin ];
    2960     }
    2961 
    2962     if ( is_wp_error( $result ) ) {
     2969        $plugin_update_data = current( $result );
     2970        /*
     2971         * If the `update_plugins` site transient is empty (e.g. when you update
     2972         * two plugins in quick succession before the transient repopulates),
     2973         * this may be the return.
     2974         *
     2975         * Preferably something can be done to ensure `update_plugins` isn't empty.
     2976         * For now, surface some sort of error here.
     2977         */
     2978        if ( $plugin_update_data === true ) {
     2979            wp_send_json_error( $status );
     2980        }
     2981        $plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
     2982        if ( $plugin_data['Version'] ) {
     2983            $status['newVersion'] = sprintf( __( 'Version %s' ), $plugin_data['Version'] );
     2984        }
     2985        wp_send_json_success( $status );
     2986    } else if ( is_wp_error( $result ) ) {
    29632987        $status['error'] = $result->get_error_message();
    29642988        wp_send_json_error( $status );
    2965     }
    2966 
    2967     wp_send_json_success( $status );
     2989    } else if ( is_bool( $result ) && ! $result ) {
     2990        $status['errorCode'] = 'unable_to_connect_to_filesystem';
     2991        $status['error'] = __( 'Unable to connect to the filesystem. Please confirm your credentials.' );
     2992        wp_send_json_error( $status );
     2993    }
    29682994}
    29692995
  • trunk/src/wp-admin/includes/file.php

    r31219 r31811  
    11931193    return false;
    11941194}
     1195
     1196/**
     1197 * Print the credentials modal when needed 
     1198 *
     1199 * @since 4.2.0
     1200 */
     1201function wp_print_request_filesystem_credentials_modal() {
     1202    $filesystem_method = get_filesystem_method();
     1203    ob_start();
     1204    $filesystem_credentials_are_stored = request_filesystem_credentials( self_admin_url() );
     1205    ob_end_clean();
     1206    $request_filesystem_credentials = ( $filesystem_method != 'direct' && ! $filesystem_credentials_are_stored );
     1207    if ( ! $request_filesystem_credentials ) {
     1208        return;
     1209    }
     1210    ?>
     1211    <div id="request-filesystem-credentials-dialog" class="notification-dialog-wrap request-filesystem-credentials-dialog">
     1212        <div class="notification-dialog-background"></div>
     1213        <div class="notification-dialog">
     1214            <div class="request-filesystem-credentials-dialog-content">
     1215                <?php request_filesystem_credentials( site_url() ); ?>
     1216            <div>
     1217        </div>
     1218    </div>
     1219    <?php
     1220}
  • trunk/src/wp-admin/js/updates.js

    r31755 r31811  
    2323
    2424    /**
     25     * Whether filesystem credentials need to be requested from the user.
     26     *
     27     * @since 4.2.0
     28     *
     29     * @var bool
     30     */
     31    wp.updates.shouldRequestFilesystemCredentials = null;
     32
     33    /**
     34     * Filesystem credentials to be packaged along with the request.
     35     *
     36     * @since  4.2.0
     37     *
     38     * @var object
     39     */
     40    wp.updates.filesystemCredentials = {
     41        ftp: {
     42            host: null,
     43            username: null,
     44            password: null,
     45            connectionType: null
     46        },
     47        ssh: {
     48            publicKey: null,
     49            privateKey: null
     50        }
     51    };
     52
     53    /**
    2554     * Flag if we're waiting for an install/update to complete.
    2655     *
     
    3059     */
    3160    wp.updates.updateLock = false;
     61
     62    /**
     63     * * Flag if we've done an install or update successfully.
     64     *
     65     * @since 4.2.0
     66     *
     67     * @var bool
     68     */
     69    wp.updates.updateDoneSuccessfully = false;
    3270
    3371    /**
     
    124162
    125163        var data = {
    126             '_ajax_nonce': wp.updates.ajaxNonce,
    127             'plugin':      plugin,
    128             'slug':        slug
     164            _ajax_nonce:     wp.updates.ajaxNonce,
     165            plugin:          plugin,
     166            slug:            slug,
     167            username:        wp.updates.filesystemCredentials.ftp.username,
     168            password:        wp.updates.filesystemCredentials.ftp.password,
     169            hostname:        wp.updates.filesystemCredentials.ftp.hostname,
     170            connection_type: wp.updates.filesystemCredentials.ftp.connectionType,
     171            public_key:      wp.updates.filesystemCredentials.ssh.publicKey,
     172            private_key:     wp.updates.filesystemCredentials.ssh.privateKey
    129173        };
    130174
    131175        wp.ajax.post( 'update-plugin', data )
    132176            .done( wp.updates.updateSuccess )
    133             .fail( wp.updates.updateError )
    134             .always( wp.updates.updateAlways );
     177            .fail( wp.updates.updateError );
    135178    };
    136179
     
    148191            $( '#' + response.slug ).addClass( 'updated' ).removeClass( 'update' );
    149192            $( '#' + response.slug + '-update' ).addClass( 'updated' ).removeClass( 'update' );
     193            // Update the version number in the row.
     194            var newText = $( '#' + response.slug ).find('.plugin-version-author-uri').html().replace( response.oldVersion, response.newVersion );
     195            $( '#' + response.slug ).find('.plugin-version-author-uri').html( newText );
    150196        } else if ( 'plugin-install' === pagenow ) {
    151197            $message = $( '.plugin-card-' + response.slug ).find( '.update-now' );
     
    158204
    159205        wp.updates.decrementCount( 'plugin' );
     206
     207        wp.updates.updateDoneSuccessfully = true;
     208
     209        /*
     210         * The lock can be released since the update was successful,
     211         * and any other updates can commence.
     212         */
     213        wp.updates.updateLock = false;
     214        wp.updates.queueChecker();
    160215    };
    161216
     
    169224    wp.updates.updateError = function( response ) {
    170225        var $message;
     226        wp.updates.updateDoneSuccessfully = false;
     227        if ( response.errorCode && response.errorCode == 'unable_to_connect_to_filesystem' ) {
     228            wp.updates.credentialError( response, 'update-plugin' );
     229            return;
     230        }
    171231        if ( 'plugins' === pagenow || 'plugins-network' === pagenow ) {
    172232            $message = $( '#' + response.slug ).next().find( '.update-message' );
     
    177237        $message.text( wp.updates.l10n.updateFailed );
    178238        wp.a11y.speak( wp.updates.l10n.updateFailed );
    179     };
    180 
    181     /**
    182      * After an update attempt has completed, check the queue.
    183      *
    184      * @since 4.2.0
    185      */
    186     wp.updates.updateAlways = function() {
    187         wp.updates.updateLock = false;
    188         wp.updates.queueChecker();
    189     };
    190 
     239
     240    };
     241
     242    /**
     243     * Show an error message in the request for credentials form.
     244     *
     245     * @param {string} message
     246     * @since 4.2.0
     247     */
     248    wp.updates.showErrorInCredentialsForm = function( message ) {
     249        var $notificationDialog = $( '.notification-dialog' );
     250
     251        // Remove any existing error
     252        $notificationDialog.find( '.error' ).remove();
     253
     254        $notificationDialog.find( 'h3' ).after( '<div class="error">' + message + '</div>' );
     255    };
    191256
    192257    /**
     
    217282
    218283        var data = {
    219             '_ajax_nonce': wp.updates.ajaxNonce,
    220             'slug':        slug
     284            _ajax_nonce:     wp.updates.ajaxNonce,
     285            slug:            slug,
     286            username:        wp.updates.filesystemCredentials.ftp.username,
     287            password:        wp.updates.filesystemCredentials.ftp.password,
     288            hostname:        wp.updates.filesystemCredentials.ftp.hostname,
     289            connection_type: wp.updates.filesystemCredentials.ftp.connectionType,
     290            public_key:      wp.updates.filesystemCredentials.ssh.publicKey,
     291            private_key:     wp.updates.filesystemCredentials.ssh.privateKey
    221292        };
    222293
    223294        wp.ajax.post( 'install-plugin', data )
    224295            .done( wp.updates.installSuccess )
    225             .fail( wp.updates.installError )
    226             .always( wp.updates.updateAlways );
     296            .fail( wp.updates.installError );
    227297    };
    228298
     
    240310        $message.text( wp.updates.l10n.installed );
    241311        wp.a11y.speak( wp.updates.l10n.installedMsg );
     312        wp.updates.updateDoneSuccessfully = true;
     313
     314        /*
     315         * The lock can be released since the update was successful,
     316         * and any other updates can commence.
     317         */
     318        wp.updates.updateLock = false;
     319        wp.updates.queueChecker();
    242320    };
    243321
     
    251329    wp.updates.installError = function( response ) {
    252330        var $message = $( '.plugin-card-' + response.slug ).find( '.install-now' );
     331        wp.updates.updateDoneSuccessfully = false;
     332        if ( response.errorCode && response.errorCode == 'unable_to_connect_to_filesystem' ) {
     333            wp.updates.credentialError( response, 'install-plugin' );
     334            return;
     335        }
    253336
    254337        $message.removeClass( 'updating-message' );
    255338        $message.text( wp.updates.l10n.installNow );
    256     };
    257 
     339
     340        wp.updates.updateLock = false;
     341    };
     342
     343    /**
     344     * Events that need to happen when there is a credential error
     345     *
     346     * @since 4.2.0
     347     */
     348    wp.updates.credentialError = function( response, type ) {
     349        wp.updates.updateQueue.push( {
     350            'type': type,
     351            'data': {
     352                // Not cool that we're depending on response for this data.
     353                // This would feel more whole in a view all tied together.
     354                plugin: response.plugin,
     355                slug: response.slug
     356            }
     357        } );
     358        wp.updates.showErrorInCredentialsForm( response.error );
     359        wp.updates.requestFilesystemCredentials();
     360    };
    258361
    259362    /**
     
    283386    };
    284387
     388
     389    /**
     390     * Request the users filesystem credentials if we don't have them already
     391     *
     392     * @since 4.2.0
     393     */
     394    wp.updates.requestFilesystemCredentials = function() {
     395        if ( wp.updates.updateDoneSuccessfully === false ) {
     396            wp.updates.updateLock = true;
     397            $( 'body' ).addClass( 'modal-open' );
     398            $( '#request-filesystem-credentials-dialog' ).show();
     399        }
     400    };
     401
    285402    $( document ).ready( function() {
     403        /*
     404         * Check whether a user needs to submit filesystem credentials based on whether
     405         * the form was output on the page server-side.
     406         *
     407         * @see {wp_print_request_filesystem_credentials_modal() in PHP}
     408         */
     409        wp.updates.shouldRequestFilesystemCredentials = ( $( '#request-filesystem-credentials-dialog' ).length <= 0 ) ? false : true;
     410
     411        // File system credentials form submit noop-er / handler.
     412        $( '#request-filesystem-credentials-dialog form' ).on( 'submit', function() {
     413            // Persist the credentials input by the user for the duration of the page load.
     414            wp.updates.filesystemCredentials.ftp.hostname = $('#hostname').val();
     415            wp.updates.filesystemCredentials.ftp.username = $('#username').val();
     416            wp.updates.filesystemCredentials.ftp.password = $('#password').val();
     417            wp.updates.filesystemCredentials.ftp.connectionType = $('input[name="connection_type"]:checked').val();
     418            wp.updates.filesystemCredentials.ssh.publicKey = $('#public_key').val();
     419            wp.updates.filesystemCredentials.ssh.privateKey = $('#private_key').val();
     420
     421            $( '#request-filesystem-credentials-dialog' ).hide();
     422            $( 'body' ).removeClass( 'modal-open' );
     423
     424            // Unlock and invoke the queue.
     425            wp.updates.updateLock = false;
     426            wp.updates.queueChecker();
     427
     428            return false;
     429        });
     430
     431        // Click handler for plugin updates in List Table view.
    286432        $( '.plugin-update-tr .update-link' ).on( 'click', function( e ) {
    287433            e.preventDefault();
     434            if ( wp.updates.shouldRequestFilesystemCredentials && ! wp.updates.updateLock ) {
     435                wp.updates.requestFilesystemCredentials();
     436            }
    288437            var $row = $( e.target ).parents( '.plugin-update-tr' );
    289438            wp.updates.updatePlugin( $row.data( 'plugin' ), $row.data( 'slug' ) );
     
    316465        $( '.plugin-card .install-now' ).on( 'click', function( e ) {
    317466            e.preventDefault();
     467            if ( wp.updates.shouldRequestFilesystemCredentials && ! wp.updates.updateLock ) {
     468                wp.updates.requestFilesystemCredentials();
     469            }
    318470            var $button = $( e.target );
    319471            if ( $button.hasClass( 'button-disabled' ) ) {
  • trunk/src/wp-admin/plugin-install.php

    r31755 r31811  
    129129do_action( "install_plugins_$tab", $paged ); ?>
    130130</div>
    131 <?php
     131
     132<?php
     133wp_print_request_filesystem_credentials_modal();
     134
    132135/**
    133136 * WordPress Administration Template Footer.
  • trunk/src/wp-admin/plugins.php

    r31755 r31811  
    477477
    478478<?php
     479wp_print_request_filesystem_credentials_modal();
     480
    479481include(ABSPATH . 'wp-admin/admin-footer.php');
Note: See TracChangeset for help on using the changeset viewer.