Make WordPress Core

Changeset 31811


Ignore:
Timestamp:
03/18/2015 03:17:59 AM (12 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.