File "updates-20241117132709-20250226224943.js"
Full Path: /home2/sdektunc/cepali.edu.mx/wp-admin/network/css/css/css/css/css/css/css/css/css/updates-20241117132709-20250226224943.js
File size: 68 KB
MIME-type: text/plain
Charset: utf-8
/**
* Functions for ajaxified updates, deletions and installs inside the WordPress admin.
*
* @version 4.2.0
* @output wp-admin/js/updates.js
*/
/* global pagenow, _wpThemeSettings */
/**
* @param {jQuery} $ jQuery object.
* @param {object} wp WP object.
* @param {object} settings WP Updates settings.
* @param {string} settings.ajax_nonce Ajax nonce.
* @param {object=} settings.plugins Base names of plugins in their different states.
* @param {Array} settings.plugins.all Base names of all plugins.
* @param {Array} settings.plugins.active Base names of active plugins.
* @param {Array} settings.plugins.inactive Base names of inactive plugins.
* @param {Array} settings.plugins.upgrade Base names of plugins with updates available.
* @param {Array} settings.plugins.recently_activated Base names of recently activated plugins.
* @param {Array} settings.plugins['auto-update-enabled'] Base names of plugins set to auto-update.
* @param {Array} settings.plugins['auto-update-disabled'] Base names of plugins set to not auto-update.
* @param {object=} settings.themes Slugs of themes in their different states.
* @param {Array} settings.themes.all Slugs of all themes.
* @param {Array} settings.themes.upgrade Slugs of themes with updates available.
* @param {Arrat} settings.themes.disabled Slugs of disabled themes.
* @param {Array} settings.themes['auto-update-enabled'] Slugs of themes set to auto-update.
* @param {Array} settings.themes['auto-update-disabled'] Slugs of themes set to not auto-update.
* @param {object=} settings.totals Combined information for available update counts.
* @param {number} settings.totals.count Holds the amount of available updates.
*/
(function( $, wp, settings ) {
var $document = $( document ),
__ = wp.i18n.__,
_x = wp.i18n._x,
_n = wp.i18n._n,
_nx = wp.i18n._nx,
sprintf = wp.i18n.sprintf;
wp = wp || {};
/**
* The WP Updates object.
*
* @since 4.2.0
*
* @namespace wp.updates
*/
wp.updates = {};
/**
* Removed in 5.5.0, needed for back-compatibility.
*
* @since 4.2.0
* @deprecated 5.5.0
*
* @type {object}
*/
wp.updates.l10n = {
searchResults: '',
searchResultsLabel: '',
noPlugins: '',
noItemsSelected: '',
updating: '',
pluginUpdated: '',
themeUpdated: '',
update: '',
updateNow: '',
pluginUpdateNowLabel: '',
updateFailedShort: '',
updateFailed: '',
pluginUpdatingLabel: '',
pluginUpdatedLabel: '',
pluginUpdateFailedLabel: '',
updatingMsg: '',
updatedMsg: '',
updateCancel: '',
beforeunload: '',
installNow: '',
pluginInstallNowLabel: '',
installing: '',
pluginInstalled: '',
themeInstalled: '',
installFailedShort: '',
installFailed: '',
pluginInstallingLabel: '',
themeInstallingLabel: '',
pluginInstalledLabel: '',
themeInstalledLabel: '',
pluginInstallFailedLabel: '',
themeInstallFailedLabel: '',
installingMsg: '',
installedMsg: '',
importerInstalledMsg: '',
aysDelete: '',
aysDeleteUninstall: '',
aysBulkDelete: '',
aysBulkDeleteThemes: '',
deleting: '',
deleteFailed: '',
pluginDeleted: '',
themeDeleted: '',
livePreview: '',
activatePlugin: '',
activateTheme: '',
activatePluginLabel: '',
activateThemeLabel: '',
activateImporter: '',
activateImporterLabel: '',
unknownError: '',
connectionError: '',
nonceError: '',
pluginsFound: '',
noPluginsFound: '',
autoUpdatesEnable: '',
autoUpdatesEnabling: '',
autoUpdatesEnabled: '',
autoUpdatesDisable: '',
autoUpdatesDisabling: '',
autoUpdatesDisabled: '',
autoUpdatesError: ''
};
wp.updates.l10n = window.wp.deprecateL10nObject( 'wp.updates.l10n', wp.updates.l10n, '5.5.0' );
/**
* User nonce for ajax calls.
*
* @since 4.2.0
*
* @type {string}
*/
wp.updates.ajaxNonce = settings.ajax_nonce;
/**
* Current search term.
*
* @since 4.6.0
*
* @type {string}
*/
wp.updates.searchTerm = '';
/**
* Whether filesystem credentials need to be requested from the user.
*
* @since 4.2.0
*
* @type {bool}
*/
wp.updates.shouldRequestFilesystemCredentials = false;
/**
* Filesystem credentials to be packaged along with the request.
*
* @since 4.2.0
* @since 4.6.0 Added `available` property to indicate whether credentials have been provided.
*
* @type {Object}
* @property {Object} filesystemCredentials.ftp Holds FTP credentials.
* @property {string} filesystemCredentials.ftp.host FTP host. Default empty string.
* @property {string} filesystemCredentials.ftp.username FTP user name. Default empty string.
* @property {string} filesystemCredentials.ftp.password FTP password. Default empty string.
* @property {string} filesystemCredentials.ftp.connectionType Type of FTP connection. 'ssh', 'ftp', or 'ftps'.
* Default empty string.
* @property {Object} filesystemCredentials.ssh Holds SSH credentials.
* @property {string} filesystemCredentials.ssh.publicKey The public key. Default empty string.
* @property {string} filesystemCredentials.ssh.privateKey The private key. Default empty string.
* @property {string} filesystemCredentials.fsNonce Filesystem credentials form nonce.
* @property {bool} filesystemCredentials.available Whether filesystem credentials have been provided.
* Default 'false'.
*/
wp.updates.filesystemCredentials = {
ftp: {
host: '',
username: '',
password: '',
connectionType: ''
},
ssh: {
publicKey: '',
privateKey: ''
},
fsNonce: '',
available: false
};
/**
* Whether we're waiting for an Ajax request to complete.
*
* @since 4.2.0
* @since 4.6.0 More accurately named `ajaxLocked`.
*
* @type {bool}
*/
wp.updates.ajaxLocked = false;
/**
* Admin notice template.
*
* @since 4.6.0
*
* @type {function}
*/
wp.updates.adminNotice = wp.template( 'wp-updates-admin-notice' );
/**
* Update queue.
*
* If the user tries to update a plugin while an update is
* already happening, it can be placed in this queue to perform later.
*
* @since 4.2.0
* @since 4.6.0 More accurately named `queue`.
*
* @type {Array.object}
*/
wp.updates.queue = [];
/**
* Holds a jQuery reference to return focus to when exiting the request credentials modal.
*
* @since 4.2.0
*
* @type {jQuery}
*/
wp.updates.$elToReturnFocusToFromCredentialsModal = undefined;
/**
* Adds or updates an admin notice.
*
* @since 4.6.0
*
* @param {Object} data
* @param {*=} data.selector Optional. Selector of an element to be replaced with the admin notice.
* @param {string=} data.id Optional. Unique id that will be used as the notice's id attribute.
* @param {string=} data.className Optional. Class names that will be used in the admin notice.
* @param {string=} data.message Optional. The message displayed in the notice.
* @param {number=} data.successes Optional. The amount of successful operations.
* @param {number=} data.errors Optional. The amount of failed operations.
* @param {Array=} data.errorMessages Optional. Error messages of failed operations.
*
*/
wp.updates.addAdminNotice = function( data ) {
var $notice = $( data.selector ),
$headerEnd = $( '.wp-header-end' ),
$adminNotice;
delete data.selector;
$adminNotice = wp.updates.adminNotice( data );
// Check if this admin notice already exists.
if ( ! $notice.length ) {
$notice = $( '#' + data.id );
}
if ( $notice.length ) {
$notice.replaceWith( $adminNotice );
} else if ( $headerEnd.length ) {
$headerEnd.after( $adminNotice );
} else {
if ( 'customize' === pagenow ) {
$( '.customize-themes-notifications' ).append( $adminNotice );
} else {
$( '.wrap' ).find( '> h1' ).after( $adminNotice );
}
}
$document.trigger( 'wp-updates-notice-added' );
};
/**
* Handles Ajax requests to WordPress.
*
* @since 4.6.0
*
* @param {string} action The type of Ajax request ('update-plugin', 'install-theme', etc).
* @param {Object} data Data that needs to be passed to the ajax callback.
* @return {$.promise} A jQuery promise that represents the request,
* decorated with an abort() method.
*/
wp.updates.ajax = function( action, data ) {
var options = {};
if ( wp.updates.ajaxLocked ) {
wp.updates.queue.push( {
action: action,
data: data
} );
// Return a Deferred object so callbacks can always be registered.
return $.Deferred();
}
wp.updates.ajaxLocked = true;
if ( data.success ) {
options.success = data.success;
delete data.success;
}
if ( data.error ) {
options.error = data.error;
delete data.error;
}
options.data = _.extend( data, {
action: action,
_ajax_nonce: wp.updates.ajaxNonce,
_fs_nonce: wp.updates.filesystemCredentials.fsNonce,
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
} );
return wp.ajax.send( options ).always( wp.updates.ajaxAlways );
};
/**
* Actions performed after every Ajax request.
*
* @since 4.6.0
*
* @param {Object} response
* @param {Array=} response.debug Optional. Debug information.
* @param {string=} response.errorCode Optional. Error code for an error that occurred.
*/
wp.updates.ajaxAlways = function( response ) {
if ( ! response.errorCode || 'unable_to_connect_to_filesystem' !== response.errorCode ) {
wp.updates.ajaxLocked = false;
wp.updates.queueChecker();
}
if ( 'undefined' !== typeof response.debug && window.console && window.console.log ) {
_.map( response.debug, function( message ) {
// Remove all HTML tags and write a message to the console.
window.console.log( wp.sanitize.stripTagsAndEncodeText( message ) );
} );
}
};
/**
* Refreshes update counts everywhere on the screen.
*
* @since 4.7.0
*/
wp.updates.refreshCount = function() {
var $adminBarUpdates = $( '#wp-admin-bar-updates' ),
$dashboardNavMenuUpdateCount = $( 'a[href="update-core.php"] .update-plugins' ),
$pluginsNavMenuUpdateCount = $( 'a[href="plugins.php"] .update-plugins' ),
$appearanceNavMenuUpdateCount = $( 'a[href="themes.php"] .update-plugins' ),
itemCount;
$adminBarUpdates.find( '.ab-label' ).text( settings.totals.counts.total );
$adminBarUpdates.find( '.updates-available-text' ).text(
sprintf(
/* translators: %s: Total number of updates available. */
_n( '%s update available', '%s updates available', settings.totals.counts.total ),
settings.totals.counts.total
)
);
// Remove the update count from the toolbar if it's zero.
if ( 0 === settings.totals.counts.total ) {
$adminBarUpdates.find( '.ab-label' ).parents( 'li' ).remove();
}
// Update the "Updates" menu item.
$dashboardNavMenuUpdateCount.each( function( index, element ) {
element.className = element.className.replace( /count-\d+/, 'count-' + settings.totals.counts.total );
} );
if ( settings.totals.counts.total > 0 ) {
$dashboardNavMenuUpdateCount.find( '.update-count' ).text( settings.totals.counts.total );
} else {
$dashboardNavMenuUpdateCount.remove();
}
// Update the "Plugins" menu item.
$pluginsNavMenuUpdateCount.each( function( index, element ) {
element.className = element.className.replace( /count-\d+/, 'count-' + settings.totals.counts.plugins );
} );
if ( settings.totals.counts.total > 0 ) {
$pluginsNavMenuUpdateCount.find( '.plugin-count' ).text( settings.totals.counts.plugins );
} else {
$pluginsNavMenuUpdateCount.remove();
}
// Update the "Appearance" menu item.
$appearanceNavMenuUpdateCount.each( function( index, element ) {
element.className = element.className.replace( /count-\d+/, 'count-' + settings.totals.counts.themes );
} );
if ( settings.totals.counts.total > 0 ) {
$appearanceNavMenuUpdateCount.find( '.theme-count' ).text( settings.totals.counts.themes );
} else {
$appearanceNavMenuUpdateCount.remove();
}
// Update list table filter navigation.
if ( 'plugins' === pagenow || 'plugins-network' === pagenow ) {
itemCount = settings.totals.counts.plugins;
} else if ( 'themes' === pagenow || 'themes-network' === pagenow ) {
itemCount = settings.totals.counts.themes;
}
if ( itemCount > 0 ) {
$( '.subsubsub .upgrade .count' ).text( '(' + itemCount + ')' );
} else {
$( '.subsubsub .upgrade' ).remove();
$( '.subsubsub li:last' ).html( function() { return $( this ).children(); } );
}
};
/**
* Sends a message from a modal to the main screen to update buttons in plugin cards.
*
* @since 6.5.0
*
* @param {Object} data An object of data to use for the button.
* @param {string} data.slug The plugin's slug.
* @param {string} data.text The text to use for the button.
* @param {string} data.ariaLabel The value for the button's aria-label attribute. An empty string removes the attribute.
* @param {string=} data.status Optional. An identifier for the status.
* @param {string=} data.removeClasses Optional. A space-separated list of classes to remove from the button.
* @param {string=} data.addClasses Optional. A space-separated list of classes to add to the button.
* @param {string=} data.href Optional. The button's URL.
* @param {string=} data.pluginName Optional. The plugin's name.
* @param {string=} data.plugin Optional. The plugin file, relative to the plugins directory.
*/
wp.updates.setCardButtonStatus = function( data ) {
var target = window.parent === window ? null : window.parent;
$.support.postMessage = !! window.postMessage;
if ( false !== $.support.postMessage && null !== target && -1 === window.parent.location.pathname.indexOf( 'index.php' ) ) {
target.postMessage( JSON.stringify( data ), window.location.origin );
}
};
/**
* Decrements the update counts throughout the various menus.
*
* This includes the toolbar, the "Updates" menu item and the menu items
* for plugins and themes.
*
* @since 3.9.0
*
* @param {string} type The type of item that was updated or deleted.
* Can be 'plugin', 'theme'.
*/
wp.updates.decrementCount = function( type ) {
settings.totals.counts.total = Math.max( --settings.totals.counts.total, 0 );
if ( 'plugin' === type ) {
settings.totals.counts.plugins = Math.max( --settings.totals.counts.plugins, 0 );
} else if ( 'theme' === type ) {
settings.totals.counts.themes = Math.max( --settings.totals.counts.themes, 0 );
}
wp.updates.refreshCount( type );
};
/**
* Sends an Ajax request to the server to update a plugin.
*
* @since 4.2.0
* @since 4.6.0 More accurately named `updatePlugin`.
*
* @param {Object} args Arguments.
* @param {string} args.plugin Plugin basename.
* @param {string} args.slug Plugin slug.
* @param {updatePluginSuccess=} args.success Optional. Success callback. Default: wp.updates.updatePluginSuccess
* @param {updatePluginError=} args.error Optional. Error callback. Default: wp.updates.updatePluginError
* @return {$.promise} A jQuery promise that represents the request,
* decorated with an abort() method.
*/
wp.updates.updatePlugin = function( args ) {
var $updateRow, $card, $message, message,
$adminBarUpdates = $( '#wp-admin-bar-updates' ),
buttonText = __( 'Updating...' ),
isPluginInstall = 'plugin-install' === pagenow || 'plugin-install-network' === pagenow;
args = _.extend( {
success: wp.updates.updatePluginSuccess,
error: wp.updates.updatePluginError
}, args );
if ( 'plugins' === pagenow || 'plugins-network' === pagenow ) {
$updateRow = $( 'tr[data-plugin="' + args.plugin + '"]' );
$message = $updateRow.find( '.update-message' ).removeClass( 'notice-error' ).addClass( 'updating-message notice-warning' ).find( 'p' );
message = sprintf(
/* translators: %s: Plugin name and version. */
_x( 'Updating %s...', 'plugin' ),
$updateRow.find( '.plugin-title strong' ).text()
);
} else if ( isPluginInstall ) {
$card = $( '.plugin-card-' + args.slug + ', #plugin-information-footer' );
$message = $card.find( '.update-now' ).addClass( 'updating-message' );
message = sprintf(
/* translators: %s: Plugin name and version. */
_x( 'Updating %s...', 'plugin' ),
$message.data( 'name' )
);
// Remove previous error messages, if any.
$card.removeClass( 'plugin-card-update-failed' ).find( '.notice.notice-error' ).remove();
}
$adminBarUpdates.addClass( 'spin' );
if ( $message.html() !== __( 'Updating...' ) ) {
$message.data( 'originaltext', $message.html() );
}
$message
.attr( 'aria-label', message )
.text( buttonText );
$document.trigger( 'wp-plugin-updating', args );
if ( isPluginInstall && 'plugin-information-footer' === $card.attr( 'id' ) ) {
wp.updates.setCardButtonStatus(
{
status: 'updating-plugin',
slug: args.slug,
addClasses: 'updating-message',
text: buttonText,
ariaLabel: message
}
);
}
return wp.updates.ajax( 'update-plugin', args );
};
/**
* Updates the UI appropriately after a successful plugin update.
*
* @since 4.2.0
* @since 4.6.0 More accurately named `updatePluginSuccess`.
* @since 5.5.0 Auto-update "time to next update" text cleared.
*
* @param {Object} response Response from the server.
* @param {string} response.slug Slug of the plugin to be updated.
* @param {string} response.plugin Basename of the plugin to be updated.
* @param {string} response.pluginName Name of the plugin to be updated.
* @param {string} response.oldVersion Old version of the plugin.
* @param {string} response.newVersion New version of the plugin.
*/
wp.updates.updatePluginSuccess = function( response ) {
var $pluginRow, $updateMessage, newText,
$adminBarUpdates = $( '#wp-admin-bar-updates' ),
buttonText = _x( 'Updated!', 'plugin' ),
ariaLabel = sprintf(
/* translators: %s: Plugin name and version. */
_x( '%s updated!', 'plugin' ),
response.pluginName
);
if ( 'plugins' === pagenow || 'plugins-network' === pagenow ) {
$pluginRow = $( 'tr[data-plugin="' + response.plugin + '"]' )
.removeClass( 'update is-enqueued' )
.addClass( 'updated' );
$updateMessage = $pluginRow.find( '.update-message' )
.removeClass( 'updating-message notice-warning' )
.addClass( 'updated-message notice-success' ).find( 'p' );
// Update the version number in the row.
newText = $pluginRow.find( '.plugin-version-author-uri' ).html().replace( response.oldVersion, response.newVersion );
$pluginRow.find( '.plugin-version-author-uri' ).html( newText );
// Clear the "time to next auto-update" text.
$pluginRow.find( '.auto-update-time' ).empty();
} else if ( 'plugin-install' === pagenow || 'plugin-install-network' === pagenow ) {
$updateMessage = $( '.plugin-card-' + response.slug + ', #plugin-information-footer' ).find( '.update-now' )
.removeClass( 'updating-message' )
.addClass( 'button-disabled updated-message' );
}
$adminBarUpdates.removeClass( 'spin' );
$updateMessage
.attr( 'aria-label', ariaLabel )
.text( buttonText );
wp.a11y.speak( __( 'Update completed successfully.' ) );
if ( 'plugin_install_from_iframe' !== $updateMessage.attr( 'id' ) ) {
wp.updates.decrementCount( 'plugin' );
} else {
wp.updates.setCardButtonStatus(
{
status: 'updated-plugin',
slug: response.slug,
removeClasses: 'updating-message',
addClasses: 'button-disabled updated-message',
text: buttonText,
ariaLabel: ariaLabel
}
);
}
$document.trigger( 'wp-plugin-update-success', response );
};
/**
* Updates the UI appropriately after a failed plugin update.
*
* @since 4.2.0
* @since 4.6.0 More accurately named `updatePluginError`.
*
* @param {Object} response Response from the server.
* @param {string} response.slug Slug of the plugin to be updated.
* @param {string} response.plugin Basename of the plugin to be updated.
* @param {string=} response.pluginName Optional. Name of the plugin to be updated.
* @param {string} response.errorCode Error code for the error that occurred.
* @param {string} response.errorMessage The error that occurred.
*/
wp.updates.updatePluginError = function( response ) {
var $pluginRow, $card, $message, errorMessage, buttonText, ariaLabel,
$adminBarUpdates = $( '#wp-admin-bar-updates' );
if ( ! wp.updates.isValidResponse( response, 'update' ) ) {
return;
}
if ( wp.updates.maybeHandleCredentialError( response, 'update-plugin' ) ) {
return;
}
errorMessage = sprintf(
/* translators: %s: Error string for a failed update. */
__( 'Update failed: %s' ),
response.errorMessage
);
if ( 'plugins' === pagenow || 'plugins-network' === pagenow ) {
$pluginRow = $( 'tr[data-plugin="' + response.plugin + '"]' ).removeClass( 'is-enqueued' );
if ( response.plugin ) {
$message = $( 'tr[data-plugin="' + response.plugin + '"]' ).find( '.update-message' );
} else {
$message = $( 'tr[data-slug="' + response.slug + '"]' ).find( '.update-message' );
}
$message.removeClass( 'updating-message notice-warning' ).addClass( 'notice-error' ).find( 'p' ).html( errorMessage );
if ( response.pluginName ) {
$message.find( 'p' )
.attr(
'aria-label',
sprintf(
/* translators: %s: Plugin name and version. */
_x( '%s update failed.', 'plugin' ),
response.pluginName
)
);
} else {
$message.find( 'p' ).removeAttr( 'aria-label' );
}
} else if ( 'plugin-install' === pagenow || 'plugin-install-network' === pagenow ) {
buttonText = __( 'Update failed.' );
$card = $( '.plugin-card-' + response.slug + ', #plugin-information-footer' )
.append( wp.updates.adminNotice( {
className: 'update-message notice-error notice-alt is-dismissible',
message: errorMessage
} ) );
if ( $card.hasClass( 'plugin-card-' + response.slug ) ) {
$card.addClass( 'plugin-card-update-failed' );
}
$card.find( '.update-now' )
.text( buttonText )
.removeClass( 'updating-message' );
if ( response.pluginName ) {
ariaLabel = sprintf(
/* translators: %s: Plugin name and version. */
_x( '%s update failed.', 'plugin' ),
response.pluginName
);
$card.find( '.update-now' ).attr( 'aria-label', ariaLabel );
} else {
ariaLabel = '';
$card.find( '.update-now' ).removeAttr( 'aria-label' );
}
$card.on( 'click', '.notice.is-dismissible .notice-dismiss', function() {
// Use same delay as the total duration of the notice fadeTo + slideUp animation.
setTimeout( function() {
$card
.removeClass( 'plugin-card-update-failed' )
.find( '.column-name a' ).trigger( 'focus' );
$card.find( '.update-now' )
.attr( 'aria-label', false )
.text( __( 'Update Now' ) );
}, 200 );
} );
}
$adminBarUpdates.removeClass( 'spin' );
wp.a11y.speak( errorMessage, 'assertive' );
if ( 'plugin-information-footer' === $card.attr('id' ) ) {
wp.updates.setCardButtonStatus(
{
status: 'plugin-update-failed',
slug: response.slug,
removeClasses: 'updating-message',
text: buttonText,
ariaLabel: ariaLabel
}
);
}
$document.trigger( 'wp-plugin-update-error', response );
};
/**
* Sends an Ajax request to the server to install a plugin.
*
* @since 4.6.0
*
* @param {Object} args Arguments.
* @param {string} args.slug Plugin identifier in the WordPress.org Plugin repository.
* @param {installPluginSuccess=} args.success Optional. Success callback. Default: wp.updates.installPluginSuccess
* @param {installPluginError=} args.error Optional. Error callback. Default: wp.updates.installPluginError
* @return {$.promise} A jQuery promise that represents the request,
* decorated with an abort() method.
*/
wp.updates.installPlugin = function( args ) {
var $card = $( '.plugin-card-' + args.slug + ', #plugin-information-footer' ),
$message = $card.find( '.install-now' ),
buttonText = __( 'Installing...' ),
ariaLabel;
args = _.extend( {
success: wp.updates.installPluginSuccess,
error: wp.updates.installPluginError
}, args );
if ( 'import' === pagenow ) {
$message = $( '[data-slug="' + args.slug + '"]' );
}
if ( $message.html() !== __( 'Installing...' ) ) {
$message.data( 'originaltext', $message.html() );
}
ariaLabel = sprintf(
/* translators: %s: Plugin name and version. */
_x( 'Installing %s...', 'plugin' ),
$message.data( 'name' )
);
$message
.addClass( 'updating-message' )
.attr( 'aria-label', ariaLabel )
.text( buttonText );
wp.a11y.speak( __( 'Installing... please wait.' ) );
// Remove previous error messages, if any.
$card.removeClass( 'plugin-card-install-failed' ).find( '.notice.notice-error' ).remove();
$document.trigger( 'wp-plugin-installing', args );
if ( 'plugin-information-footer' === $message.parent().attr( 'id' ) ) {
wp.updates.setCardButtonStatus(
{
status: 'installing-plugin',
slug: args.slug,
addClasses: 'updating-message',
text: buttonText,
ariaLabel: ariaLabel
}
);
}
return wp.updates.ajax( 'install-plugin', args );
};
/**
* Updates the UI appropriately after a successful plugin install.
*
* @since 4.6.0
*
* @param {Object} response Response from the server.
* @param {string} response.slug Slug of the installed plugin.
* @param {string} response.pluginName Name of the installed plugin.
* @param {string} response.activateUrl URL to activate the just installed plugin.
*/
wp.updates.installPluginSuccess = function( response ) {
var $message = $( '.plugin-card-' + response.slug + ', #plugin-information-footer' ).find( '.install-now' ),
buttonText = _x( 'Installed!', 'plugin' ),
ariaLabel = sprintf(
/* translators: %s: Plugin name and version. */
_x( '%s installed!', 'plugin' ),
response.pluginName
);
$message
.removeClass( 'updating-message' )
.addClass( 'updated-message installed button-disabled' )
.attr( 'aria-label', ariaLabel )
.text( buttonText );
wp.a11y.speak( __( 'Installation completed successfully.' ) );
$document.trigger( 'wp-plugin-install-success', response );
if ( response.activateUrl ) {
setTimeout( function() {
wp.updates.checkPluginDependencies( {
slug: response.slug
} );
}, 1000 );
}
if ( 'plugin-information-footer' === $message.parent().attr( 'id' ) ) {
wp.updates.setCardButtonStatus(
{
status: 'installed-plugin',
slug: response.slug,
removeClasses: 'updating-message',
addClasses: 'updated-message installed button-disabled',
text: buttonText,
ariaLabel: ariaLabel
}
);
}
};
/**
* Updates the UI appropriately after a failed plugin install.
*
* @since 4.6.0
*
* @param {Object} response Response from the server.
* @param {string} response.slug Slug of the plugin to be installed.
* @param {string=} response.pluginName Optional. Name of the plugin to be installed.
* @param {string} response.errorCode Error code for the error that occurred.
* @param {string} response.errorMessage The error that occurred.
*/
wp.updates.installPluginError = function( response ) {
var $card = $( '.plugin-card-' + response.slug + ', #plugin-information-footer' ),
$button = $card.find( '.install-now' ),
buttonText = __( 'Installation failed.' ),
ariaLabel = sprintf(
/* translators: %s: Plugin name and version. */
_x( '%s installation failed', 'plugin' ),
$button.data( 'name' )
),
errorMessage;
if ( ! wp.updates.isValidResponse( response, 'install' ) ) {
return;
}
if ( wp.updates.maybeHandleCredentialError( response, 'install-plugin' ) ) {
return;
}
errorMessage = sprintf(
/* translators: %s: Error string for a failed installation. */
__( 'Installation failed: %s' ),
response.errorMessage
);
$card
.addClass( 'plugin-card-update-failed' )
.append( '<div class="notice notice-error notice-alt is-dismissible"><p>' + errorMessage + '</p></div>' );
$card.on( 'click', '.notice.is-dismissible .notice-dismiss', function() {
// Use same delay as the total duration of the notice fadeTo + slideUp animation.
setTimeout( function() {
$card
.removeClass( 'plugin-card-update-failed' )
.find( '.column-name a' ).trigger( 'focus' );
}, 200 );
} );
$button
.removeClass( 'updating-message' ).addClass( 'button-disabled' )
.attr( 'aria-label', ariaLabel )
.text( buttonText );
wp.a11y.speak( errorMessage, 'assertive' );
wp.updates.setCardButtonStatus(
{
status: 'plugin-install-failed',
slug: response.slug,
removeClasses: 'updating-message',
addClasses: 'button-disabled',
text: buttonText,
ariaLabel: ariaLabel
}
);
$document.trigger( 'wp-plugin-install-error', response );
};
/**
* Sends an Ajax request to the server to check a plugin's dependencies.
*
* @since 6.5.0
*
* @param {Object} args Arguments.
* @param {string} args.slug Plugin identifier in the WordPress.org Plugin repository.
* @param {checkPluginDependenciesSuccess=} args.success Optional. Success callback. Default: wp.updates.checkPluginDependenciesSuccess
* @param {checkPluginDependenciesError=} args.error Optional. Error callback. Default: wp.updates.checkPluginDependenciesError
* @return {$.promise} A jQuery promise that represents the request,
* decorated with an abort() method.
*/
wp.updates.checkPluginDependencies = function( args ) {
args = _.extend( {
success: wp.updates.checkPluginDependenciesSuccess,
error: wp.updates.checkPluginDependenciesError
}, args );
wp.a11y.speak( __( 'Checking plugin dependencies... please wait.' ) );
$document.trigger( 'wp-checking-plugin-dependencies', args );
return wp.updates.ajax( 'check_plugin_dependencies', args );
};
/**
* Updates the UI appropriately after a successful plugin dependencies check.
*
* @since 6.5.0
*
* @param {Object} response Response from the server.
* @param {string} response.slug Slug of the checked plugin.
* @param {string} response.pluginName Name of the checked plugin.
* @param {string} response.plugin The plugin file, relative to the plugins directory.
* @param {string} response.activateUrl URL to activate the just checked plugin.
*/
wp.updates.checkPluginDependenciesSuccess = function( response ) {
var $message = $( '.plugin-card-' + response.slug + ', #plugin-information-footer' ).find( '.install-now' ),
buttonText, ariaLabel;
// Transform the 'Install' button into an 'Activate' button.
$message
.removeClass( 'install-now installed button-disabled updated-message' )
.addClass( 'activate-now button-primary' )
.attr( 'href', response.activateUrl );
wp.a11y.speak( __( 'Plugin dependencies check completed successfully.' ) );
$document.trigger( 'wp-check-plugin-dependencies-success', response );
if ( 'plugins-network' === pagenow ) {
buttonText = _x( 'Network Activate', 'plugin' );
ariaLabel = sprintf(
/* translators: %s: Plugin name. */
_x( 'Network Activate %s', 'plugin' ),
response.pluginName
);
$message
.attr( 'aria-label', ariaLabel )
.text( buttonText );
} else {
buttonText = _x( 'Activate', 'plugin' );
ariaLabel = sprintf(
/* translators: %s: Plugin name. */
_x( 'Activate %s', 'plugin' ),
response.pluginName
);
$message
.attr( 'aria-label', ariaLabel )
.attr( 'data-name', response.pluginName )
.attr( 'data-slug', response.slug )
.attr( 'data-plugin', response.plugin )
.text( buttonText );
}
if ( 'plugin-information-footer' === $message.parent().attr( 'id' ) ) {
wp.updates.setCardButtonStatus(
{
status: 'dependencies-check-success',
slug: response.slug,
removeClasses: 'install-now installed button-disabled updated-message',
addClasses: 'activate-now button-primary',
text: buttonText,
ariaLabel: ariaLabel,
pluginName: response.pluginName,
plugin: response.plugin,
href: response.activateUrl
}
);
}
};
/**
* Updates the UI appropriately after a failed plugin dependencies check.
*
* @since 6.5.0
*
* @param {Object} response Response from the server.
* @param {string} response.slug Slug of the plugin to be checked.
* @param {string=} response.pluginName Optional. Name of the plugin to be checked.
* @param {string} response.errorCode Error code for the error that occurred.
* @param {string} response.errorMessage The error that occurred.
*/
wp.updates.checkPluginDependenciesError = function( response ) {
var $message = $( '.plugin-card-' + response.slug + ', #plugin-information-footer' ).find( '.install-now' ),
buttonText = _x( 'Activate', 'plugin' ),
ariaLabel = sprintf(
/* translators: 1: Plugin name, 2. The reason the plugin cannot be activated. */
_x( 'Cannot activate %1$s. %2$s', 'plugin' ),
response.pluginName,
response.errorMessage
),
errorMessage;
if ( ! wp.updates.isValidResponse( response, 'check-dependencies' ) ) {
return;
}
errorMessage = sprintf(
/* translators: %s: Error string for a failed activation. */
__( 'Activation failed: %s' ),
response.errorMessage
);
wp.a11y.speak( errorMessage, 'assertive' );
$document.trigger( 'wp-check-plugin-dependencies-error', response );
$message
.removeClass( 'install-now installed updated-message' )
.addClass( 'activate-now button-primary' )
.attr( 'aria-label', ariaLabel )
.text( buttonText );
if ( 'plugin-information-footer' === $message.parent().attr('id' ) ) {
wp.updates.setCardButtonStatus(
{
status: 'dependencies-check-failed',
slug: response.slug,
removeClasses: 'install-now installed updated-message',
addClasses: 'activate-now button-primary',
text: buttonText,
ariaLabel: ariaLabel
}
);
}
};
/**
* Sends an Ajax request to the server to activate a plugin.
*
* @since 6.5.0
*
* @param {Object} args Arguments.
* @param {string} args.name The name of the plugin.
* @param {string} args.slug Plugin identifier in the WordPress.org Plugin repository.
* @param {string} args.plugin The plugin file, relative to the plugins directory.
* @param {activatePluginSuccess=} args.success Optional. Success callback. Default: wp.updates.activatePluginSuccess
* @param {activatePluginError=} args.error Optional. Error callback. Default: wp.updates.activatePluginError
* @return {$.promise} A jQuery promise that represents the request,
* decorated with an abort() method.
*/
wp.updates.activatePlugin = function( args ) {
var $message = $( '.plugin-card-' + args.slug + ', #plugin-information-footer' ).find( '.activate-now, .activating-message' );
args = _.extend( {
success: wp.updates.activatePluginSuccess,
error: wp.updates.activatePluginError
}, args );
wp.a11y.speak( __( 'Activating... please wait.' ) );
$document.trigger( 'wp-activating-plugin', args );
if ( 'plugin-information-footer' === $message.parent().attr( 'id' ) ) {
wp.updates.setCardButtonStatus(
{
status: 'activating-plugin',
slug: args.slug,
removeClasses: 'installed updated-message button-primary',
addClasses: 'activating-message',
text: __( 'Activating...' ),
ariaLabel: sprintf(
/* translators: %s: Plugin name. */
_x( 'Activating %s', 'plugin' ),
args.name
)
}
);
}
return wp.updates.ajax( 'activate-plugin', args );
};
/**
* Updates the UI appropriately after a successful plugin activation.
*
* @since 6.5.0
*
* @param {Object} response Response from the server.
* @param {string} response.slug Slug of the activated plugin.
* @param {string} response.pluginName Name of the activated plugin.
* @param {string} response.plugin The plugin file, relative to the plugins directory.
*/
wp.updates.activatePluginSuccess = function( response ) {
var $message = $( '.plugin-card-' + response.slug + ', #plugin-information-footer' ).find( '.activating-message' ),
buttonText = _x( 'Activated!', 'plugin' ),
ariaLabel = sprintf(
/* translators: %s: The plugin name. */
'%s activated successfully.',
response.pluginName
);
wp.a11y.speak( __( 'Activation completed successfully.' ) );
$document.trigger( 'wp-plugin-activate-success', response );
$message
.removeClass( 'activating-message' )
.addClass( 'activated-message button-disabled' )
.attr( 'aria-label', ariaLabel )
.text( buttonText );
if ( 'plugin-information-footer' === $message.parent().attr( 'id' ) ) {
wp.updates.setCardButtonStatus(
{
status: 'activated-plugin',
slug: response.slug,
removeClasses: 'activating-message',
addClasses: 'activated-message button-disabled',
text: buttonText,
ariaLabel: ariaLabel
}
);
}
setTimeout( function() {
$message.removeClass( 'activated-message' )
.text( _x( 'Active', 'plugin' ) );
if ( 'plugin-information-footer' === $message.parent().attr( 'id' ) ) {
wp.updates.setCardButtonStatus(
{
status: 'plugin-active',
slug: response.slug,
removeClasses: 'activated-message',
text: _x( 'Active', 'plugin' ),
ariaLabel: sprintf(
/* translators: %s: The plugin name. */
'%s is active.',
response.pluginName
)
}
);
}
}, 1000 );
};
/**
* Updates the UI appropriately after a failed plugin activation.
*
* @since 6.5.0
*
* @param {Object} response Response from the server.
* @param {string} response.slug Slug of the plugin to be activated.
* @param {string=} response.pluginName Optional. Name of the plugin to be activated.
* @param {string} response.errorCode Error code for the error that occurred.
* @param {string} response.errorMessage The error that occurred.
*/
wp.updates.activatePluginError = function( response ) {
var $message = $( '.plugin-card-' + response.slug + ', #plugin-information-footer' ).find( '.activating-message' ),
buttonText = __( 'Activation failed.' ),
ariaLabel = sprintf(
/* translators: %s: Plugin name. */
_x( '%s activation failed', 'plugin' ),
response.pluginName
),
errorMessage;
if ( ! wp.updates.isValidResponse( response, 'activate' ) ) {
return;
}
errorMessage = sprintf(
/* translators: %s: Error string for a failed activation. */
__( 'Activation failed: %s' ),
response.errorMessage
);
wp.a11y.speak( errorMessage, 'assertive' );
$document.trigger( 'wp-plugin-activate-error', response );
$message
.removeClass( 'install-now installed activating-message' )
.addClass( 'button-disabled' )
.attr( 'aria-label', ariaLabel )
.text( buttonText );
if ( 'plugin-information-footer' === $message.parent().attr( 'id' ) ) {
wp.updates.setCardButtonStatus(
{
status: 'plugin-activation-failed',
slug: response.slug,
removeClasses: 'install-now installed activating-message',
addClasses: 'button-disabled',
text: buttonText,
ariaLabel: ariaLabel
}
);
}
};
/**
* Updates the UI appropriately after a successful importer install.
*
* @since 4.6.0
*
* @param {Object} response Response from the server.
* @param {string} response.slug Slug of the installed plugin.
* @param {string} response.pluginName Name of the installed plugin.
* @param {string} response.activateUrl URL to activate the just installed plugin.
*/
wp.updates.installImporterSuccess = function( response ) {
wp.updates.addAdminNotice( {
id: 'install-success',
className: 'notice-success is-dismissible',
message: sprintf(
/* translators: %s: Activation URL. */
__( 'Importer installed successfully. <a href="%s">Run importer</a>' ),
response.activateUrl + '&from=import'
)
} );
$( '[data-slug="' + response.slug + '"]' )
.removeClass( 'install-now updating-message' )
.addClass( 'activate-now' )
.attr({
'href': response.activateUrl + '&from=import',
'aria-label':sprintf(
/* translators: %s: Importer name. */
__( 'Run %s' ),
response.pluginName
)
})
.text( __( 'Run Importer' ) );
wp.a11y.speak( __( 'Installation completed successfully.' ) );
$document.trigger( 'wp-importer-install-success', response );
};
/**
* Updates the UI appropriately after a failed importer install.
*
* @since 4.6.0
*
* @param {Object} response Response from the server.
* @param {string} response.slug Slug of the plugin to be installed.
* @param {string=} response.pluginName Optional. Name of the plugin to be installed.
* @param {string} response.errorCode Error code for the error that occurred.
* @param {string} response.errorMessage The error that occurred.
*/
wp.updates.installImporterError = function( response ) {
var errorMessage = sprintf(
/* translators: %s: Error string for a failed installation. */
__( 'Installation failed: %s' ),
response.errorMessage
),
$installLink = $( '[data-slug="' + response.slug + '"]' ),
pluginName = $installLink.data( 'name' );
if ( ! wp.updates.isValidResponse( response, 'install' ) ) {
return;
}
if ( wp.updates.maybeHandleCredentialError( response, 'install-plugin' ) ) {
return;
}
wp.updates.addAdminNotice( {
id: response.errorCode,
className: 'notice-error is-dismissible',
message: errorMessage
} );
$installLink
.removeClass( 'updating-message' )
.attr(
'aria-label',
sprintf(
/* translators: %s: Plugin name. */
_x( 'Install %s now', 'plugin' ),
pluginName
)
)
.text( _x( 'Install Now', 'plugin' ) );
wp.a11y.speak( errorMessage, 'assertive' );
$document.trigger( 'wp-importer-install-error', response );
};
/**
* Sends an Ajax request to the server to delete a plugin.
*
* @since 4.6.0
*
* @param {Object} args Arguments.
* @param {string} args.plugin Basename of the plugin to be deleted.
* @param {string} args.slug Slug of the plugin to be deleted.
* @param {deletePluginSuccess=} args.success Optional. Success callback. Default: wp.updates.deletePluginSuccess
* @param {deletePluginError=} args.error Optional. Error callback. Default: wp.updates.deletePluginError
* @return {$.promise} A jQuery promise that represents the request,
* decorated with an abort() method.
*/
wp.updates.deletePlugin = function( args ) {
var $link = $( '[data-plugin="' + args.plugin + '"]' ).find( '.row-actions a.delete' );
args = _.extend( {
success: wp.updates.deletePluginSuccess,
error: wp.updates.deletePluginError
}, args );
if ( $link.html() !== __( 'Deleting...' ) ) {
$link
.data( 'originaltext', $link.html() )
.text( __( 'Deleting...' ) );
}
wp.a11y.speak( __( 'Deleting...' ) );
$document.trigger( 'wp-plugin-deleting', args );
return wp.updates.ajax( 'delete-plugin', args );
};
/**
* Updates the UI appropriately after a successful plugin deletion.
*
* @since 4.6.0
*
* @param {Object} response Response from the server.
* @param {string} response.slug Slug of the plugin that was deleted.
* @param {string} response.plugin Base name of the plugin that was deleted.
* @param {string} response.pluginName Name of the plugin that was deleted.
*/
wp.updates.deletePluginSuccess = function( response ) {
// Removes the plugin and updates rows.
$( '[data-plugin="' + response.plugin + '"]' ).css( { backgroundColor: '#faafaa' } ).fadeOut( 350, function() {
var $form = $( '#bulk-action-form' ),
$views = $( '.subsubsub' ),
$pluginRow = $( this ),
$currentView = $views.find( '[aria-current="page"]' ),
$itemsCount = $( '.displaying-num' ),
columnCount = $form.find( 'thead th:not(.hidden), thead td' ).length,
pluginDeletedRow = wp.template( 'item-deleted-row' ),
/**
* Plugins Base names of plugins in their different states.
*
* @type {Object}
*/
plugins = settings.plugins,
remainingCount;
// Add a success message after deleting a plugin.
if ( ! $pluginRow.hasClass( 'plugin-update-tr' ) ) {
$pluginRow.after(
pluginDeletedRow( {
slug: response.slug,
plugin: response.plugin,
colspan: columnCount,
name: response.pluginName
} )
);
}
$pluginRow.remove();
// Remove plugin from update count.
if ( -1 !== _.indexOf( plugins.upgrade, response.plugin ) ) {
plugins.upgrade = _.without( plugins.upgrade, response.plugin );
wp.updates.decrementCount( 'plugin' );
}
// Remove from views.
if ( -1 !== _.indexOf( plugins.inactive, response.plugin ) ) {
plugins.inactive = _.without( plugins.inactive, response.plugin );
if ( plugins.inactive.length ) {
$views.find( '.inactive .count' ).text( '(' + plugins.inactive.length + ')' );
} else {
$views.find( '.inactive' ).remove();
}
}
if ( -1 !== _.indexOf( plugins.active, response.plugin ) ) {
plugins.active = _.without( plugins.active, response.plugin );
if ( plugins.active.length ) {
$views.find( '.active .count' ).text( '(' + plugins.active.length + ')' );
} else {
$views.find( '.active' ).remove();
}
}
if ( -1 !== _.indexOf( plugins.recently_activated, response.plugin ) ) {
plugins.recently_activated = _.without( plugins.recently_activated, response.plugin );
if ( plugins.recently_activated.length ) {
$views.find( '.recently_activated .count' ).text( '(' + plugins.recently_activated.length + ')' );
} else {
$views.find( '.recently_activated' ).remove();
}
}
if ( -1 !== _.indexOf( plugins['auto-update-enabled'], response.plugin ) ) {
plugins['auto-update-enabled'] = _.without( plugins['auto-update-enabled'], response.plugin );
if ( plugins['auto-update-enabled'].length ) {
$views.find( '.auto-update-enabled .count' ).text( '(' + plugins['auto-update-enabled'].length + ')' );
} else {
$views.find( '.auto-update-enabled' ).remove();
}
}
if ( -1 !== _.indexOf( plugins['auto-update-disabled'], response.plugin ) ) {
plugins['auto-update-disabled'] = _.without( plugins['auto-update-disabled'], response.plugin );
if ( plugins['auto-update-disabled'].length ) {
$views.find( '.auto-update-disabled .count' ).text( '(' + plugins['auto-update-disabled'].length + ')' );
} else {
$views.find( '.auto-update-disabled' ).remove();
}
}
plugins.all = _.without( plugins.all, response.plugin );
if ( plugins.all.length ) {
$views.find( '.all .count' ).text( '(' + plugins.all.length + ')' );
} else {
$form.find( '.tablenav' ).css( { visibility: 'hidden' } );
$views.find( '.all' ).remove();
if ( ! $form.find( 'tr.no-items' ).length ) {
$form.find( '#the-list' ).append( '<tr class="no-items"><td class="colspanchange" colspan="' + columnCount + '">' + __( 'No plugins are currently available.' ) + '</td></tr>' );
}
}
if ( $itemsCount.length && $currentView.length ) {
remainingCount = plugins[ $currentView.parent( 'li' ).attr('class') ].length;
$itemsCount.text(
sprintf(
/* translators: %s: The remaining number of plugins. */
_nx( '%s item', '%s items', remainingCount, 'plugin/plugins' ),
remainingCount
)
);
}
} );
wp.a11y.speak( _x( 'Deleted!', 'plugin' ) );
$document.trigger( 'wp-plugin-delete-success', response );
};
/**
* Updates the UI appropriately after a failed plugin deletion.
*
* @since 4.6.0
*
* @param {Object} response Response from the server.
* @param {string} response.slug Slug of the plugin to be deleted.
* @param {string} response.plugin Base name of the plugin to be deleted
* @param {string=} response.pluginName Optional. Name of the plugin to be deleted.
* @param {string} response.errorCode Error code for the error that occurred.
* @param {string} response.errorMessage The error that occurred.
*/
wp.updates.deletePluginError = function( response ) {
var $plugin, $pluginUpdateRow,
pluginUpdateRow = wp.template( 'item-update-row' ),
noticeContent = wp.updates.adminNotice( {
className: 'update-message notice-error notice-alt',
message: response.errorMessage
} );
if ( response.plugin ) {
$plugin = $( 'tr.inactive[data-plugin="' + response.plugin + '"]' );
$pluginUpdateRow = $plugin.siblings( '[data-plugin="' + response.plugin + '"]' );
} else {
$plugin = $( 'tr.inactive[data-slug="' + response.slug + '"]' );
$pluginUpdateRow = $plugin.siblings( '[data-slug="' + response.slug + '"]' );
}
if ( ! wp.updates.isValidResponse( response, 'delete' ) ) {
return;
}
if ( wp.updates.maybeHandleCredentialError( response, 'delete-plugin' ) ) {
return;
}
// Add a plugin update row if it doesn't exist yet.
if ( ! $pluginUpdateRow.length ) {
$plugin.addClass( 'update' ).after(
pluginUpdateRow( {
slug: response.slug,
plugin: response.plugin || response.slug,
colspan: $( '#bulk-action-form' ).find( 'thead th:not(.hidden), thead td' ).length,
content: noticeContent
} )
);
} else {
// Remove previous error messages, if any.
$pluginUpdateRow.find( '.notice-error' ).remove();
$pluginUpdateRow.find( '.plugin-update' ).append( noticeContent );
}
$document.trigger( 'wp-plugin-delete-error', response );
};
/**
* Sends an Ajax request to the server to update a theme.
*
* @since 4.6.0
*
* @param {Object} args Arguments.
* @param {string} args.slug Theme stylesheet.
* @param {updateThemeSuccess=} args.success Optional. Success callback. Default: wp.updates.updateThemeSuccess
* @param {updateThemeError=} args.error Optional. Error callback. Default: wp.updates.updateThemeError
* @return {$.promise} A jQuery promise that represents the request,
* decorated with an abort() method.
*/
wp.updates.updateTheme = function( args ) {
var $notice;
args = _.extend( {
success: wp.updates.updateThemeSuccess,
error: wp.updates.updateThemeError
}, args );
if ( 'themes-network' === pagenow ) {
$notice = $( '[data-slug="' + args.slug + '"]' ).find( '.update-message' ).removeClass( 'notice-error' ).addClass( 'updating-message notice-warning' ).find( 'p' );
} else if ( 'customize' === pagenow ) {
// Update the theme details UI.
$notice = $( '[data-slug="' + args.slug + '"].notice' ).removeClass( 'notice-large' );
$notice.find( 'h3' ).remove();
// Add the top-level UI, and update both.
$notice = $notice.add( $( '#customize-control-installed_theme_' + args.slug ).find( '.update-message' ) );
$notice = $notice.addClass( 'updating-message' ).find( 'p' );
} else {
$notice = $( '#update-theme' ).closest( '.notice' ).removeClass( 'notice-large' );
$notice.find( 'h3' ).remove();
$notice = $notice.add( $( '[data-slug="' + args.slug + '"]' ).find( '.update-message' ) );
$notice = $notice.addClass( 'updating-message' ).find( 'p' );
}
if ( $notice.html() !== __( 'Updating...' ) ) {
$notice.data( 'originaltext', $notice.html() );
}
wp.a11y.speak( __( 'Updating... please wait.' ) );
$notice.text( __( 'Updating...' ) );
$document.trigger( 'wp-theme-updating', args );
return wp.updates.ajax( 'update-theme', args );
};
/**
* Updates the UI appropriately after a successful theme update.
*
* @since 4.6.0
* @since 5.5.0 Auto-update "time to next update" text cleared.
*
* @param {Object} response
* @param {string} response.slug Slug of the theme to be updated.
* @param {Object} response.theme Updated theme.
* @param {string} response.oldVersion Old version of the theme.
* @param {string} response.newVersion New version of the theme.
*/
wp.updates.updateThemeSuccess = function( response ) {
var isModalOpen = $( 'body.modal-open' ).length,
$theme = $( '[data-slug="' + response.slug + '"]' ),
updatedMessage = {
className: 'updated-message notice-success notice-alt',
message: _x( 'Updated!', 'theme' )
},
$notice, newText;
if ( 'customize' === pagenow ) {
$theme = $( '.updating-message' ).siblings( '.theme-name' );
if ( $theme.length ) {
// Update the version number in the row.
newText = $theme.html().replace( response.oldVersion, response.newVersion );
$theme.html( newText );
}
$notice = $( '.theme-info .notice' ).add( wp.customize.control( 'installed_theme_' + response.slug ).container.find( '.theme' ).find( '.update-message' ) );
} else if ( 'themes-network' === pagenow ) {
$notice = $theme.find( '.update-message' );
// Update the version number in the row.
newText = $theme.find( '.theme-version-author-uri' ).html().replace( response.oldVersion, response.newVersion );
$theme.find( '.theme-version-author-uri' ).html( newText );
// Clear the "time to next auto-update" text.
$theme.find( '.auto-update-time' ).empty();
} else {
$notice = $( '.theme-info .notice' ).add( $theme.find( '.update-message' ) );
// Focus on Customize button after updating.
if ( isModalOpen ) {
$( '.load-customize:visible' ).trigger( 'focus' );
$( '.theme-info .theme-autoupdate' ).find( '.auto-update-time' ).empty();
} else {
$theme.find( '.load-customize' ).trigger( 'focus' );
}
}
wp.updates.addAdminNotice( _.extend( { selector: $notice }, updatedMessage ) );
wp.a11y.speak( __( 'Update completed successfully.' ) );
wp.updates.decrementCount( 'theme' );
$document.trigger( 'wp-theme-update-success', response );
// Show updated message after modal re-rendered.
if ( isModalOpen && 'customize' !== pagenow ) {
$( '.theme-info .theme-author' ).after( wp.updates.adminNotice( updatedMessage ) );
}
};
/**
* Updates the UI appropriately after a failed theme update.
*
* @since 4.6.0
*
* @param {Object} response Response from the server.
* @param {string} response.slug Slug of the theme to be updated.
* @param {string} response.errorCode Error code for the error that occurred.
* @param {string} response.errorMessage The error that occurred.
*/
wp.updates.updateThemeError = function( response ) {
var $theme = $( '[data-slug="' + response.slug + '"]' ),
errorMessage = sprintf(
/* translators: %s: Error string for a failed update. */
__( 'Update failed: %s' ),
response.errorMessage
),
$notice;
if ( ! wp.updates.isValidResponse( response, 'update' ) ) {
return;
}
if ( wp.updates.maybeHandleCredentialError( response, 'update-theme' ) ) {
return;
}
if ( 'customize' === pagenow ) {
$theme = wp.customize.control( 'installed_theme_' + response.slug ).container.find( '.theme' );
}
if ( 'themes-network' === pagenow ) {
$notice = $theme.find( '.update-message ' );
} else {
$notice = $( '.theme-info .notice' ).add( $theme.find( '.notice' ) );
$( 'body.modal-open' ).length ? $( '.load-customize:visible' ).trigger( 'focus' ) : $theme.find( '.load-customize' ).trigger( 'focus');
}
wp.updates.addAdminNotice( {
selector: $notice,
className: 'update-message notice-error notice-alt is-dismissible',
message: errorMessage
} );
wp.a11y.speak( errorMessage );
$document.trigger( 'wp-theme-update-error', response );
};
/**
* Sends an Ajax request to the server to install a theme.
*
* @since 4.6.0
*
* @param {Object} args
* @param {string} args.slug Theme stylesheet.
* @param {installThemeSuccess=} args.success Optional. Success callback. Default: wp.updates.installThemeSuccess
* @param {installThemeError=} args.error Optional. Error callback. Default: wp.updates.installThemeError
* @return {$.promise} A jQuery promise that represents the request,
* decorated with an abort() method.
*/
wp.updates.installTheme = function( args ) {
var $message = $( '.theme-install[data-slug="' + args.slug + '"]' );
args = _.extend( {
success: wp.updates.installThemeSuccess,
error: wp.updates.installThemeError
}, args );
$message.addClass( 'updating-message' );
$message.parents( '.theme' ).addClass( 'focus' );
if ( $message.html() !== __( 'Installing...' ) ) {
$message.data( 'originaltext', $message.html() );
}
$message
.attr(
'aria-label',
sprintf(
/* translators: %s: Theme name and version. */
_x( 'Installing %s...', 'theme' ),
$message.data( 'name' )
)
)
.text( __( 'Installing...' ) );
wp.a11y.speak( __( 'Installing... please wait.' ) );
// Remove previous error messages, if any.
$( '.install-theme-info, [data-slug="' + args.slug + '"]' ).removeClass( 'theme-install-failed' ).find( '.notice.notice-error' ).remove();
$document.trigger( 'wp-theme-installing', args );
return wp.updates.ajax( 'install-theme', args );
};
/**
* Updates the UI appropriately after a successful theme install.
*
* @since 4.6.0
*
* @param {Object} response Response from the server.
* @param {string} response.slug Slug of the theme to be installed.
* @param {string} response.customizeUrl URL to the Customizer for the just installed theme.
* @param {string} response.activateUrl URL to activate the just installed theme.
*/
wp.updates.installThemeSuccess = function( response ) {
var $card = $( '.wp-full-overlay-header, [data-slug=' + response.slug + ']' ),
$message;
$document.trigger( 'wp-theme-install-success', response );
$message = $card.find( '.button-primary' )
.removeClass( 'updating-message' )
.addClass( 'updated-message disabled' )
.attr(
'aria-label',
sprintf(
/* translators: %s: Theme name and version. */
_x( '%s installed!', 'theme' ),
response.themeName
)
)
.text( _x( 'Installed!', 'theme' ) );
wp.a11y.speak( __( 'Installation completed successfully.' ) );
setTimeout( function() {
if ( response.activateUrl ) {
// Transform the 'Install' button into an 'Activate' button.
$message
.attr( 'href', response.activateUrl )
.removeClass( 'theme-install updated-message disabled' )
.addClass( 'activate' );
if ( 'themes-network' === pagenow ) {
$message
.attr(
'aria-label',
sprintf(
/* translators: %s: Theme name. */
_x( 'Network Activate %s', 'theme' ),
response.themeName
)
)
.text( __( 'Network Enable' ) );
} else {
$message
.attr(
'aria-label',
sprintf(
/* translators: %s: Theme name. */
_x( 'Activate %s', 'theme' ),
response.themeName
)
)
.text( _x( 'Activate', 'theme' ) );
}
}
if ( response.customizeUrl ) {
// Transform the 'Preview' button into a 'Live Preview' button.
$message.siblings( '.preview' ).replaceWith( function () {
return $( '<a>' )
.attr( 'href', response.customizeUrl )
.addClass( 'button load-customize' )
.text( __( 'Live Preview' ) );
} );
}
}, 1000 );
};
/**
* Updates the UI appropriately after a failed theme install.
*
* @since 4.6.0
*
* @param {Object} response Response from the server.
* @param {string} response.slug Slug of the theme to be installed.
* @param {string} response.errorCode Error code for the error that occurred.
* @param {string} response.errorMessage The error that occurred.
*/
wp.updates.installThemeError = function( response ) {
var $card, $button,
errorMessage = sprintf(
/* translators: %s: Error string for a failed installation. */
__( 'Installation failed: %s' ),
response.errorMessage
),
$message = wp.updates.adminNotice( {
className: 'update-message notice-error notice-alt',
message: errorMessage
} );
if ( ! wp.updates.isValidResponse( response, 'install' ) ) {
return;
}
if ( wp.updates.maybeHandleCredentialError( response, 'install-theme' ) ) {
return;
}
if ( 'customize' === pagenow ) {
if ( $document.find( 'body' ).hasClass( 'modal-open' ) ) {
$button = $( '.theme-install[data-slug="' + response.slug + '"]' );
$card = $( '.theme-overlay .theme-info' ).prepend( $message );
} else {
$button = $( '.theme-install[data-slug="' + response.slug + '"]' );
$card = $button.closest( '.theme' ).addClass( 'theme-install-failed' ).append( $message );
}
wp.customize.notifications.remove( 'theme_installing' );
} else {
if ( $document.find( 'body' ).hasClass( 'full-overlay-active' ) ) {
$button = $( '.theme-install[data-slug="' + response.slug + '"]' );
$card = $( '.install-theme-info' ).prepend( $message );
} else {
$card = $( '[data-slug="' + response.slug + '"]' ).removeClass( 'focus' ).addClass( 'theme-install-failed' ).append( $message );
$button = $card.find( '.theme-install' );
}
}
$button
.removeClass( 'updating-message' )
.attr(
'aria-label',
sprintf(
/* translators: %s: Theme name and version. */
_x( '%s installation failed', 'theme' ),
$button.data( 'name' )
)
)
.text( __( 'Installation failed.' ) );
wp.a11y.speak( errorMessage, 'assertive' );
$document.trigger( 'wp-theme-install-error', response );
};
/**
* Sends an Ajax request to the server to delete a theme.
*
* @since 4.6.0
*
* @param {Object} args
* @param {string} args.slug Theme stylesheet.
* @param {deleteThemeSuccess=} args.success Optional. Success callback. Default: wp.updates.deleteThemeSuccess
* @param {deleteThemeError=} args.error Optional. Error callback. Default: wp.updates.deleteThemeError
* @return {$.promise} A jQuery promise that represents the request,
* decorated with an abort() method.
*/
wp.updates.deleteTheme = function( args ) {
var $button;
if ( 'themes' === pagenow ) {
$button = $( '.theme-actions .delete-theme' );
} else if ( 'themes-network' === pagenow ) {
$button = $( '[data-slug="' + args.slug + '"]' ).find( '.row-actions a.delete' );
}
args = _.extend( {
success: wp.updates.deleteThemeSuccess,
error: wp.updates.deleteThemeError
}, args );
if ( $button && $button.html() !== __( 'Deleting...' ) ) {
$button
.data( 'originaltext', $button.html() )
.text( __( 'Deleting...' ) );
}
wp.a11y.speak( __( 'Deleting...' ) );
// Remove previous error messages, if any.
$( '.theme-info .update-message' ).remove();
$document.trigger( 'wp-theme-deleting', args );
return wp.updates.ajax( 'delete-theme', args );
};
/**
* Updates the UI appropriately after a successful theme deletion.
*
* @since 4.6.0
*
* @param {Object} response Response from the server.
* @param {string} response.slug Slug of the theme that was deleted.
*/
wp.updates.deleteThemeSuccess = function( response ) {
var $themeRows = $( '[data-slug="' + response.slug + '"]' );
if ( 'themes-network' === pagenow ) {
// Removes the theme and updates rows.
$themeRows.css( { backgroundColor: '#faafaa' } ).fadeOut( 350, function() {
var $views = $( '.subsubsub' ),
$themeRow = $( this ),
themes = settings.themes,
deletedRow = wp.template( 'item-deleted-row' );
if ( ! $themeRow.hasClass( 'plugin-update-tr' ) ) {
$themeRow.after(
deletedRow( {
slug: response.slug,
colspan: $( '#bulk-action-form' ).find( 'thead th:not(.hidden), thead td' ).length,
name: $themeRow.find( '.theme-title strong' ).text()
} )
);
}
$themeRow.remove();
// Remove theme from update count.
if ( -1 !== _.indexOf( themes.upgrade, response.slug ) ) {
themes.upgrade = _.without( themes.upgrade, response.slug );
wp.updates.decrementCount( 'theme' );
}
// Remove from views.
if ( -1 !== _.indexOf( themes.disabled, response.slug ) ) {
themes.disabled = _.without( themes.disabled, response.slug );
if ( themes.disabled.length ) {
$views.find( '.disabled .count' ).text( '(' + themes.disabled.length + ')' );
} else {
$views.find( '.disabled' ).remove();
}
}
if ( -1 !== _.indexOf( themes['auto-update-enabled'], response.slug ) ) {
themes['auto-update-enabled'] = _.without( themes['auto-update-enabled'], response.slug );
if ( themes['auto-update-enabled'].length ) {
$views.find( '.auto-update-enabled .count' ).text( '(' + themes['auto-update-enabled'].length + ')' );
} else {
$views.find( '.auto-update-enabled' ).remove();
}
}
if ( -1 !== _.indexOf( themes['auto-update-disabled'], response.slug ) ) {
themes['auto-update-disabled'] = _.without( themes['auto-update-disabled'], response.slug );
if ( themes['auto-update-disabled'].length ) {
$views.find( '.auto-update-disabled .count' ).text( '(' + themes['auto-update-disabled'].length + ')' );
} else {
$views.find( '.auto-update-disabled' ).remove();
}
}
themes.all = _.without( themes.all, response.slug );
// There is always at least one theme available.
$views.find( '.all .count' ).text( '(' + themes.all.length + ')' );
} );
}
// DecrementCount from update count.
if ( 'themes' === pagenow ) {
var theme = _.find( _wpThemeSettings.themes, { id: response.slug } );
if ( theme.hasUpdate ) {
wp.updates.decrementCount( 'theme' );
}
}
wp.a11y.speak( _x( 'Deleted!', 'theme' ) );
$document.trigger( 'wp-theme-delete-success', response );
};
/**
* Updates the UI appropriately after a failed theme deletion.
*
* @since 4.6.0
*
* @param {Object} response Response from the server.
* @param {string} response.slug Slug of the theme to be deleted.
* @param {string} response.errorCode Error code for the error that occurred.
* @param {string} response.errorMessage The error that occurred.
*/
wp.updates.deleteThemeError = function( response ) {
var $themeRow = $( 'tr.inactive[data-slug="' + response.slug + '"]' ),
$button = $( '.theme-actions .delete-theme' ),
updateRow = wp.template( 'item-update-row' ),
$updateRow = $themeRow.siblings( '#' + response.slug + '-update' ),
errorMessage = sprintf(
/* translators: %s: Error string for a failed deletion. */
__( 'Deletion failed: %s' ),
response.errorMessage
),
$message = wp.updates.adminNotice( {
className: 'update-message notice-error notice-alt',
message: errorMessage
} );
if ( wp.updates.maybeHandleCredentialError( response, 'delete-theme' ) ) {
return;
}
if ( 'themes-network' === pagenow ) {
if ( ! $updateRow.length ) {
$themeRow.addClass( 'update' ).after(
updateRow( {
slug: response.slug,
colspan: $( '#bulk-action-form' ).find( 'thead th:not(.hidden), thead td' ).length,
content: $message
} )
);
} else {
// Remove previous error messages, if any.
$updateRow.find( '.notice-error' ).remove();
$updateRow.find( '.plugin-update' ).append( $message );
}
} else {
$( '.theme-info .theme-description' ).before( $message );
}
$button.html( $button.data( 'originaltext' ) );
wp.a11y.speak( errorMessage, 'assertive' );
$document.trigger( 'wp-theme-delete-error', response );
};
/**
* Adds the appropriate callback based on the type of action and the current page.
*
* @since 4.6.0
* @priv