diff --git a/src/wp-admin/css/forms.css b/src/wp-admin/css/forms.css
index 256a51f795..b58cf7d4cc 100644
--- a/src/wp-admin/css/forms.css
+++ b/src/wp-admin/css/forms.css
@@ -850,6 +850,26 @@ table.form-table td .updated p {
margin-bottom: 5px;
}
+/*------------------------------------------------------------------------------
+ Credentials check dialog for Install and Updates
+------------------------------------------------------------------------------*/
+
+.request-filesystem-credentials-dialog {
+ display: none;
+}
+
+.request-filesystem-credentials-dialog .notification-dialog{
+ top: 15%
+}
+
+.request-filesystem-credentials-dialog-content{
+ margin: 25px;
+}
+.request-filesystem-credentials-dialog-content input[type="text"],
+.request-filesystem-credentials-dialog-content input[type="password"]{
+ width:85%;
+}
+
/* =Media Queries
-------------------------------------------------------------- */
diff --git a/src/wp-admin/includes/ajax-actions.php b/src/wp-admin/includes/ajax-actions.php
index 81ba091519..430ae97ac9 100644
--- a/src/wp-admin/includes/ajax-actions.php
+++ b/src/wp-admin/includes/ajax-actions.php
@@ -2913,6 +2913,10 @@ function wp_ajax_install_plugin() {
if ( is_wp_error( $result ) ) {
$status['error'] = $result->get_error_message();
wp_send_json_error( $status );
+ } else if ( is_null( $result ) ) {
+ $status['errorCode'] = __( 'unable_to_connect_to_filesystem' );
+ $status['error'] = __( 'Unable to connect to the filesystem. Please confirm your credentials.' );
+ wp_send_json_error( $status );
}
$plugin_status = install_plugin_install_status( $api );
@@ -2954,17 +2958,16 @@ function wp_ajax_update_plugin() {
$upgrader = new Plugin_Upgrader( new Automatic_Upgrader_Skin() );
$result = $upgrader->bulk_upgrade( array( $plugin ) );
-
if ( is_array( $result ) ) {
- $result = $result[ $plugin ];
- }
-
- if ( is_wp_error( $result ) ) {
+ wp_send_json_success( $status );
+ } else if ( is_wp_error( $result ) ) {
$status['error'] = $result->get_error_message();
wp_send_json_error( $status );
+ } else if ( is_bool( $result ) && ! $result ) {
+ $status['errorCode'] = __( 'unable_to_connect_to_filesystem' );
+ $status['error'] = __( 'Unable to connect to the filesystem. Please confirm your credentials.' );
+ wp_send_json_error( $status );
}
-
- wp_send_json_success( $status );
}
/**
diff --git a/src/wp-admin/js/updates.js b/src/wp-admin/js/updates.js
index 109a3dccdd..47c4a960d2 100644
--- a/src/wp-admin/js/updates.js
+++ b/src/wp-admin/js/updates.js
@@ -21,6 +21,35 @@ window.wp = window.wp || {};
*/
wp.updates.l10n = window._wpUpdatesSettings.l10n;
+ /**
+ * Whether filesystem credentials need to be requested from the user.
+ *
+ * @since 4.2.0
+ *
+ * @var bool
+ */
+ wp.updates.shouldRequestFilesystemCredentials = window._wpUpdatesSettings.requestFilesystemCredentials;
+
+ /**
+ * Filesystem credentials to be packaged along with the request.
+ *
+ * @since 4.2.0
+ *
+ * @var object
+ */
+ wp.updates.filesystemCredentials = {
+ ftp: {
+ host: null,
+ username: null,
+ password: null,
+ connectionType: null
+ },
+ ssh: {
+ publicKey: null,
+ privateKey: null
+ }
+ };
+
/**
* Flag if we're waiting for an install/update to complete.
*
@@ -30,6 +59,15 @@ window.wp = window.wp || {};
*/
wp.updates.updateLock = false;
+ /**
+ * Flag if we've done an install or update successfully.
+ *
+ * @since 4.2.0
+ *
+ * @var bool
+ */
+ wp.updates.updateDoneSuccessfully = false;
+
/**
* If the user tries to install/update a plugin while an install/update is
* already happening, it can be placed in this queue to perform later.
@@ -124,8 +162,14 @@ window.wp = window.wp || {};
var data = {
'_ajax_nonce': wp.updates.ajaxNonce,
- 'plugin': plugin,
- 'slug': slug
+ 'plugin': plugin,
+ 'slug': slug,
+ username: wp.updates.filesystemCredentials.ftp.username,
+ password: wp.updates.filesystemCredentials.ftp.password,
+ hostname: wp.updates.filesystemCredentials.ftp.hostname,
+ connection_type: wp.updates.filesystemCredentials.ftp.connectionType,
+ public_key: wp.updates.filesystemCredentials.ssh.publicKey,
+ private_key: wp.updates.filesystemCredentials.ssh.privateKey
};
wp.ajax.post( 'update-plugin', data )
@@ -157,6 +201,8 @@ window.wp = window.wp || {};
wp.a11y.speak( wp.updates.l10n.updatedMsg );
wp.updates.decrementCount( 'plugin' );
+
+ wp.updates.updateDoneSuccessfully = true;
};
/**
@@ -168,6 +214,11 @@ window.wp = window.wp || {};
*/
wp.updates.updateError = function( response ) {
var $message;
+ wp.updates.updateDoneSuccessfully = false;
+ if ( response.errorCode && response.errorCode == 'unable_to_connect_to_filesystem' ) {
+ wp.updates.credentialError( response, 'update-plugin' );
+ return;
+ }
if ( 'plugins' === pagenow || 'plugins-network' === pagenow ) {
$message = $( '#' + response.slug ).next().find( '.update-message' );
} else if ( 'plugin-install' === pagenow ) {
@@ -178,6 +229,21 @@ window.wp = window.wp || {};
wp.a11y.speak( wp.updates.l10n.updateFailed );
};
+ /**
+ * Show an
+ *
+ * @param {string} message
+ * @since 4.2.0
+ */
+ wp.updates.showErrorInCredentialsForm = function( message ) {
+ var $notificationDialog = $( '.notification-dialog' );
+
+ // Remove any existing error
+ $notificationDialog.find( '.error' ).remove();
+
+ $notificationDialog.find( 'h3' ).after( '
' + message + '
' );
+ };
+
/**
* After an update attempt has completed, check the queue.
*
@@ -216,8 +282,14 @@ window.wp = window.wp || {};
wp.updates.updateLock = true;
var data = {
- '_ajax_nonce': wp.updates.ajaxNonce,
- 'slug': slug
+ '_ajax_nonce': wp.updates.ajaxNonce,
+ 'slug': slug,
+ 'username': wp.updates.filesystemCredentials.ftp.username,
+ 'password': wp.updates.filesystemCredentials.ftp.password,
+ 'hostname': wp.updates.filesystemCredentials.ftp.hostname,
+ 'connection_type': wp.updates.filesystemCredentials.ftp.connectionType,
+ 'public_key': wp.updates.filesystemCredentials.ssh.publicKey,
+ 'private_key': wp.updates.filesystemCredentials.ssh.privateKey
};
wp.ajax.post( 'install-plugin', data )
@@ -239,6 +311,7 @@ window.wp = window.wp || {};
$message.removeClass( 'updating-message' ).addClass( 'updated-message button-disabled' );
$message.text( wp.updates.l10n.installed );
wp.a11y.speak( wp.updates.l10n.installedMsg );
+ wp.updates.updateDoneSuccessfully = true;
};
/**
@@ -250,11 +323,35 @@ window.wp = window.wp || {};
*/
wp.updates.installError = function( response ) {
var $message = $( '.plugin-card-' + response.slug ).find( '.install-now' );
+ wp.updates.updateDoneSuccessfully = false;
+ if ( response.errorCode && response.errorCode == 'unable_to_connect_to_filesystem' ) {
+ wp.updates.credentialError( response, 'update-plugin' );
+ return;
+ }
$message.removeClass( 'updating-message' );
$message.text( wp.updates.l10n.installNow );
};
+ /**
+ * Events that need to happen when there is a credential error
+ *
+ * @since 4.2.0
+ */
+ wp.updates.credentialError = function( response, type ) {
+ wp.updates.updateQueue.push( {
+ 'type': type,
+ 'data': {
+ // Not cool that we're depending on response for this data.
+ // This would feel more whole in a view all tied together.
+ plugin: response.plugin,
+ slug: response.slug
+ }
+ } );
+ wp.updates.showErrorInCredentialsForm( response.error );
+ wp.updates.requestFilesystemCredentials();
+ };
+
/**
* If an install/update job has been placed in the queue, queueChecker pulls it out and runs it.
@@ -281,10 +378,45 @@ window.wp = window.wp || {};
break;
}
};
+ /**
+ * Request the users filesystem credentials if we don't have them already
+ *
+ * @since 4.2.0
+ */
+ wp.updates.requestFilesystemCredentials = function() {
+ if ( wp.updates.updateDoneSuccessfully === false ) {
+ wp.updates.updateLock = true;
+ $('#request-filesystem-credentials-dialog').show();
+ }
+ };
+ // Bind various click handlers.
$( document ).ready( function() {
+ // File system credentials form submit noop-er / handler.
+ $('#request-filesystem-credentials-dialog form').on( 'submit', function() {
+ // Persist the credentials input by the user for the duration of the page load.
+ wp.updates.filesystemCredentials.ftp.hostname = $('#hostname').val();
+ wp.updates.filesystemCredentials.ftp.username = $('#username').val();
+ wp.updates.filesystemCredentials.ftp.password = $('#password').val();
+ wp.updates.filesystemCredentials.ftp.connectionType = $('input[name="connection_type"]:checked').val();
+ wp.updates.filesystemCredentials.ssh.publicKey = $('#public_key').val();
+ wp.updates.filesystemCredentials.ssh.privateKey = $('#private_key').val();
+
+ $('#request-filesystem-credentials-dialog').hide();
+
+ // Unlock and invoke the queue.
+ wp.updates.updateLock = false;
+ wp.updates.queueChecker();
+
+ return false;
+ });
+
+ // Click handler for plugin updates in List Table view.
$( '.plugin-update-tr .update-link' ).on( 'click', function( e ) {
e.preventDefault();
+ if ( wp.updates.shouldRequestFilesystemCredentials === '1' && ! wp.updates.updateLock ) {
+ wp.updates.requestFilesystemCredentials();
+ }
var $row = $( e.target ).parents( '.plugin-update-tr' );
wp.updates.updatePlugin( $row.data( 'plugin' ), $row.data( 'slug' ) );
} );
@@ -315,6 +447,10 @@ window.wp = window.wp || {};
$( '.plugin-card .install-now' ).on( 'click', function( e ) {
e.preventDefault();
+ if ( wp.updates.shouldRequestFilesystemCredentials === '1' && ! wp.updates.updateLock ) {
+ wp.updates.requestFilesystemCredentials();
+ }
+
var $button = $( e.target );
if ( $button.hasClass( 'button-disabled' ) ) {
return;
diff --git a/src/wp-admin/plugin-install.php b/src/wp-admin/plugin-install.php
index 03085c7813..3c20127109 100644
--- a/src/wp-admin/plugin-install.php
+++ b/src/wp-admin/plugin-install.php
@@ -128,6 +128,16 @@ if ( $tab !== 'upload' ) {
*/
do_action( "install_plugins_$tab", $paged ); ?>
+
+
+
+
+
+
+
+
+
+
add( 'updates', "/wp-admin/js/updates$suffix.js", array( 'jquery', 'wp-util', 'wp-a11y' ) );
+
+ /*
+ * Determine whether the user will need to enter filesystem credentials
+ * on the front-end.
+ */
+ require_once(ABSPATH . 'wp-admin/includes/file.php');
+ $filesystem_method = get_filesystem_method();
+ ob_start();
+ $filesystem_credentials_are_stored = request_filesystem_credentials( self_admin_url() );
+ ob_end_clean();
+ $request_filesystem_credentials = ( $filesystem_method != 'direct' && ! $filesystem_credentials_are_stored ) ? 1 : 0;
+
did_action( 'init' ) && $scripts->localize( 'updates', '_wpUpdatesSettings', array(
'ajax_nonce' => wp_create_nonce( 'updates' ),
+ 'requestFilesystemCredentials' => $request_filesystem_credentials,
'l10n' => array(
'updating' => __( 'Updating...' ),
'updated' => __( 'Updated!' ),