diff --git a/src/wp-admin/css/common.css b/src/wp-admin/css/common.css index 705e64d942..9f873bd1d0 100644 --- a/src/wp-admin/css/common.css +++ b/src/wp-admin/css/common.css @@ -2275,15 +2275,47 @@ body.iframe { display: block; } -.importers td { - padding-right: 14px; -} - .importers { font-size: 16px; width: auto; } +.importers td { + padding-right: 14px; + line-height: 1.5em; +} + +.importers .import-system { + max-width: 250px; +} + +.importers td.desc { + max-width: 500px; +} + +.importer-title, +.importer-desc, +.importer-action { + display: block; +} + +.importer-title { + color: #000; + font-size: 14px; + font-weight: 400; + margin-bottom: .2em; +} + +.importer-action { + line-height: 20px; /* Same as with .updating-message */ + color: #ddd; + margin-bottom: 1em; +} + +.not-installed-main-site .importer-action { + color: #555; +} + #post-body #post-body-content #namediv h3, /* Back-compat for pre-4.4 */ #post-body #post-body-content #namediv h2 { margin-top: 0; diff --git a/src/wp-admin/import.php b/src/wp-admin/import.php index 962db681a2..5183766230 100644 --- a/src/wp-admin/import.php +++ b/src/wp-admin/import.php @@ -30,10 +30,12 @@ get_current_screen()->set_help_sidebar( '

' . __('Support Forums') . '

' ); -if ( current_user_can( 'install_plugins' ) ) +if ( current_user_can( 'install_plugins' ) ) { + // List of popular importer plugins from the WordPress.org API. $popular_importers = wp_get_popular_importers(); -else - $popular_importers = array(); +} else { + $popular_importers = array(); +} // Detect and redirect invalid importers like 'movabletype', which is registered as 'mt' if ( ! empty( $_GET['invalid'] ) && isset( $popular_importers[ $_GET['invalid'] ] ) ) { @@ -66,7 +68,7 @@ $parent_file = 'tools.php';

$pop_data ) { continue; if ( isset( $importers[ $pop_data['importer-id'] ] ) ) continue; + + // Fill the array of registered (already installed) importers with data of the popular importers from the WordPress.org API. $importers[ $pop_data['importer-id'] ] = array( $pop_data['name'], $pop_data['description'], 'install' => $pop_data['plugin-slug'] ); } @@ -85,43 +89,106 @@ if ( empty( $importers ) ) { ?> - $data) { - $action = ''; + $data ) { + $plugin_slug = $action = ''; + $is_plugin_installed = false; + if ( isset( $data['install'] ) ) { $plugin_slug = $data['install']; + if ( file_exists( WP_PLUGIN_DIR . '/' . $plugin_slug ) ) { - // Looks like Importer is installed, But not active + // Looks like an importer is installed, but not active. $plugins = get_plugins( '/' . $plugin_slug ); - if ( !empty($plugins) ) { - $keys = array_keys($plugins); + if ( ! empty( $plugins ) ) { + $keys = array_keys( $plugins ); $plugin_file = $plugin_slug . '/' . $keys[0]; - $action = '' . $data[0] . ''; + $url = wp_nonce_url( add_query_arg( array( + 'action' => 'activate', + 'plugin' => $plugin_file, + 'from' => 'import', + ), admin_url( 'plugins.php' ) ), 'activate-plugin_' . $plugin_file ); + $action = sprintf( + '%s', + esc_url( $url ), + /* translators: %s: Importer name */ + esc_attr( sprintf( __( 'Run %s' ), $data[0] ) ), + __( 'Run Importer' ) + ); + + $is_plugin_installed = true; } } - if ( empty($action) ) { + + if ( empty( $action ) ) { if ( is_main_site() ) { - $action = '' . $data[0] . ''; + $url = wp_nonce_url( add_query_arg( array( + 'action' => 'install-plugin', + 'plugin' => $plugin_slug, + 'from' => 'import', + ), self_admin_url( 'update.php' ) ), 'install-plugin_' . $plugin_slug ); + $action = sprintf( + '%5$s', + esc_url( $url ), + esc_attr( $plugin_slug ), + esc_attr( $data[0] ), + /* translators: %s: Importer name */ + esc_attr( sprintf( __( 'Install %s' ), $data[0] ) ), + __( 'Install Now' ) + ); } else { - $action = $data[0]; - $data[1] = sprintf( __( 'This importer is not installed. Please install importers from the main site.' ), get_admin_url( $current_site->blog_id, 'import.php' ) ); + $action = sprintf( + /* translators: URL to wp-admin/import.php */ + __( 'This importer is not installed. Please install importers from the main site.' ), + get_admin_url( get_current_network_id(), 'import.php' ) + ); } } } else { - $action = "{$data[0]}"; + $url = add_query_arg( array( + 'import' => $importer_id, + ), self_admin_url( 'admin.php' ) ); + $action = sprintf( + '%3$s', + esc_url( $url ), + /* translators: %s: Importer name */ + esc_attr( sprintf( __( 'Run %s' ), $data[0] ) ), + __( 'Run Importer' ) + ); + + $is_plugin_installed = true; + } + + if ( ! $is_plugin_installed && is_main_site() ) { + $url = add_query_arg( array( + 'tab' => 'plugin-information', + 'plugin' => $plugin_slug, + 'from' => 'import', + 'TB_iframe' => 'true', + 'width' => 600, + 'height' => 550, + ), network_admin_url( 'plugin-install.php' ) ); + $action .= sprintf( + ' | %3$s', + esc_url( $url ), + /* translators: %s: Importer name */ + esc_attr( sprintf( __( 'More information about %s' ), $data[0] ) ), + __( 'Details' ) + ); } echo " - - - + + + "; } -?> - + ?>
$action{$data[1]}
+ {$data[0]} + {$action} + + {$data[1]} +
get_locale(), + 'version' => $wp_version, + ), 'http://api.wordpress.org/core/importers/1.1/' ); $options = array( 'user-agent' => 'WordPress/' . $wp_version . '; ' . home_url() ); $response = wp_remote_get( $url, $options ); $popular_importers = json_decode( wp_remote_retrieve_body( $response ), true ); - if ( is_array( $popular_importers ) ) - set_site_transient( 'popular_importers_' . $locale, $popular_importers, 2 * DAY_IN_SECONDS ); - else + if ( is_array( $popular_importers ) ) { + set_site_transient( $cache_key, $popular_importers, 2 * DAY_IN_SECONDS ); + } else { $popular_importers = false; + } } if ( is_array( $popular_importers ) ) { @@ -157,49 +162,49 @@ function wp_get_popular_importers() { // slug => name, description, plugin slug, and register_importer() slug 'blogger' => array( 'name' => __( 'Blogger' ), - 'description' => __( 'Install the Blogger importer to import posts, comments, and users from a Blogger blog.' ), + 'description' => __( 'Import posts, comments, and users from a Blogger blog.' ), 'plugin-slug' => 'blogger-importer', 'importer-id' => 'blogger', ), 'wpcat2tag' => array( 'name' => __( 'Categories and Tags Converter' ), - 'description' => __( 'Install the category/tag converter to convert existing categories to tags or tags to categories, selectively.' ), + 'description' => __( 'Convert existing categories to tags or tags to categories, selectively.' ), 'plugin-slug' => 'wpcat2tag-importer', 'importer-id' => 'wp-cat2tag', ), 'livejournal' => array( 'name' => __( 'LiveJournal' ), - 'description' => __( 'Install the LiveJournal importer to import posts from LiveJournal using their API.' ), + 'description' => __( 'Import posts from LiveJournal using their API.' ), 'plugin-slug' => 'livejournal-importer', 'importer-id' => 'livejournal', ), 'movabletype' => array( 'name' => __( 'Movable Type and TypePad' ), - 'description' => __( 'Install the Movable Type importer to import posts and comments from a Movable Type or TypePad blog.' ), + 'description' => __( 'Import posts and comments from a Movable Type or TypePad blog.' ), 'plugin-slug' => 'movabletype-importer', 'importer-id' => 'mt', ), 'opml' => array( 'name' => __( 'Blogroll' ), - 'description' => __( 'Install the blogroll importer to import links in OPML format.' ), + 'description' => __( 'Import links in OPML format.' ), 'plugin-slug' => 'opml-importer', 'importer-id' => 'opml', ), 'rss' => array( 'name' => __( 'RSS' ), - 'description' => __( 'Install the RSS importer to import posts from an RSS feed.' ), + 'description' => __( 'Import posts from an RSS feed.' ), 'plugin-slug' => 'rss-importer', 'importer-id' => 'rss', ), 'tumblr' => array( 'name' => __( 'Tumblr' ), - 'description' => __( 'Install the Tumblr importer to import posts & media from Tumblr using their API.' ), + 'description' => __( 'Import posts & media from Tumblr using their API.' ), 'plugin-slug' => 'tumblr-importer', 'importer-id' => 'tumblr', ), 'wordpress' => array( 'name' => 'WordPress', - 'description' => __( 'Install the WordPress importer to import posts, pages, comments, custom fields, categories, and tags from a WordPress export file.' ), + 'description' => __( 'Import posts, pages, comments, custom fields, categories, and tags from a WordPress export file.' ), 'plugin-slug' => 'wordpress-importer', 'importer-id' => 'wordpress', ), diff --git a/src/wp-admin/js/updates.js b/src/wp-admin/js/updates.js index 24a8186a24..8107426a50 100644 --- a/src/wp-admin/js/updates.js +++ b/src/wp-admin/js/updates.js @@ -503,11 +503,11 @@ }, args ); if ( 'import' === pagenow ) { - $message = $( 'a[href*="' + args.slug + '"]' ); - } else { - $message.text( wp.updates.l10n.installing ); + $message = $( '[data-slug="' + args.slug + '"]' ); } + $message.text( wp.updates.l10n.installing ); + $message .addClass( 'updating-message' ) .attr( 'aria-label', wp.updates.l10n.pluginInstallingLabel.replace( '%s', $message.data( 'name' ) ) ); @@ -625,11 +625,14 @@ message: wp.updates.l10n.importerInstalledMsg.replace( '%s', response.activateUrl + '&from=import' ) } ); - $( 'a[href*="' + response.slug + '"]' ) - .removeClass( 'thickbox open-plugin-details-modal updating-message' ) - .off( 'click' ) - .attr( 'href', response.activateUrl + '&from=import' ) - .attr( 'title', wp.updates.l10n.activateImporter ); + $( '[data-slug="' + response.slug + '"]' ) + .removeClass( 'install-now updating-message' ) + .addClass( 'activate-now' ) + .attr({ + 'href': response.activateUrl + '&from=import', + 'aria-label': wp.updates.l10n.activateImporterLabel.replace( '%s', response.pluginName ) + }) + .text( wp.updates.l10n.activateImporter ); wp.a11y.speak( wp.updates.l10n.installedMsg, 'polite' ); @@ -649,7 +652,9 @@ * @param {string} response.errorMessage The error that occurred. */ wp.updates.installImporterError = function( response ) { - var errorMessage = wp.updates.l10n.installFailed.replace( '%s', response.errorMessage ); + var errorMessage = wp.updates.l10n.installFailed.replace( '%s', response.errorMessage ), + $installLink = $( '[data-slug="' + response.slug + '"]' ), + pluginName = $installLink.data( 'name' ); if ( ! wp.updates.isValidResponse( response, 'install' ) ) { return; @@ -665,7 +670,10 @@ message: errorMessage } ); - $( 'a[href*="' + response.slug + '"]' ).removeClass( 'updating-message' ); + $installLink + .removeClass( 'updating-message' ) + .text( wp.updates.l10n.installNow ) + .attr( 'aria-label', wp.updates.l10n.installNowLabel.replace( '%s', pluginName ) ); wp.a11y.speak( errorMessage, 'assertive' ); @@ -1765,6 +1773,44 @@ } ); } ); + /** + * Click handler for importer plugins installs in the Import screen. + * + * @since 4.6.0 + * + * @param {Event} event Event interface. + */ + $document.on( 'click', '.importer-item .install-now', function( event ) { + var $button = $( event.target ), + pluginName = $( this ).data( 'name' ); + + event.preventDefault(); + + if ( $button.hasClass( 'updating-message' ) ) { + return; + } + + if ( wp.updates.shouldRequestFilesystemCredentials && ! wp.updates.ajaxLocked ) { + wp.updates.requestFilesystemCredentials( event ); + + $document.on( 'credential-modal-cancel', function() { + + $button + .removeClass( 'updating-message' ) + .text( wp.updates.l10n.installNow ) + .attr( 'aria-label', wp.updates.l10n.installNowLabel.replace( '%s', pluginName ) ); + + wp.a11y.speak( wp.updates.l10n.updateCancel, 'polite' ); + } ); + } + + wp.updates.installPlugin( { + slug: $button.data( 'slug' ), + success: wp.updates.installImporterSuccess, + error: wp.updates.installImporterError + } ); + } ); + /** * Click handler for plugin deletions. * diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php index 759d15876d..e078886bc5 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -607,13 +607,13 @@ function wp_default_scripts( &$scripts ) { 'update' => __( 'Update' ), 'updateNow' => __( 'Update Now' ), 'updateFailedShort' => __( 'Update Failed!' ), - /* translators: Error string for a failed update */ + /* translators: %s: Error string for a failed update */ 'updateFailed' => __( 'Update Failed: %s' ), - /* translators: Plugin name and version */ + /* translators: %s: Plugin name and version */ 'updatingLabel' => __( 'Updating %s...' ), // No ellipsis. - /* translators: Plugin name and version */ + /* translators: %s: Plugin name and version */ 'updatedLabel' => __( '%s updated!' ), - /* translators: Plugin name and version */ + /* translators: %s: Plugin name and version */ 'updateFailedLabel' => __( '%s update failed' ), /* translators: JavaScript accessible string */ 'updatingMsg' => __( 'Updating... please wait.' ), // No ellipsis. @@ -623,27 +623,29 @@ function wp_default_scripts( &$scripts ) { 'updateCancel' => __( 'Update canceled.' ), 'beforeunload' => __( 'Updates may not complete if you navigate away from this page.' ), 'installNow' => __( 'Install Now' ), + /* translators: %s: Plugin name */ + 'installNowLabel' => __( 'Install %s' ), 'installing' => __( 'Installing...' ), 'installed' => __( 'Installed!' ), 'installFailedShort' => __( 'Install Failed!' ), - /* translators: Error string for a failed installation */ + /* translators: %s: Error string for a failed installation */ 'installFailed' => __( 'Installation failed: %s' ), - /* translators: Plugin name and version */ + /* translators: %s: Plugin name and version */ 'pluginInstallingLabel' => _x( 'Installing %s...', 'plugin' ), // no ellipsis - /* translators: Theme name and version */ + /* translators: %s: Theme name and version */ 'themeInstallingLabel' => _x( 'Installing %s...', 'theme' ), // no ellipsis - /* translators: Plugin name and version */ + /* translators: %s: Plugin name and version */ 'pluginInstalledLabel' => _x( '%s installed!', 'plugin' ), - /* translators: Theme name and version */ + /* translators: %s: Theme name and version */ 'themeInstalledLabel' => _x( '%s installed!', 'theme' ), - /* translators: Plugin name and version */ + /* translators: %s: Plugin name and version */ 'pluginInstallFailedLabel' => _x( '%s installation failed', 'plugin' ), - /* translators: Theme name and version */ + /* translators: %s: Theme name and version */ 'themeInstallFailedLabel' => _x( '%s installation failed', 'theme' ), 'installingMsg' => __( 'Installing... please wait.' ), 'installedMsg' => __( 'Installation completed successfully.' ), - /* translators: Activation URL */ - 'importerInstalledMsg' => __( 'Importer installed successfully. Activate plugin & run importer' ), + /* translators: %s: Activation URL */ + 'importerInstalledMsg' => __( 'Importer installed successfully. Run importer' ), /* translators: %s: Theme name */ 'aysDelete' => __( 'Are you sure you want to delete %s?' ), /* translators: %s: Plugin name */ @@ -661,7 +663,9 @@ function wp_default_scripts( &$scripts ) { 'activatePluginLabel' => is_network_admin() ? _x( 'Network Activate %s', 'plugin' ) : _x( 'Activate %s', 'plugin' ), /* translators: %s: Theme name */ 'activateThemeLabel' => is_network_admin() ? _x( 'Network Activate %s', 'theme' ) : _x( 'Activate %s', 'theme' ), - 'activateImporter' => __( 'Activate importer' ), + 'activateImporter' => __( 'Run Importer' ), + /* translators: %s: Importer name */ + 'activateImporterLabel' => __( 'Run %s' ), 'unknownError' => __( 'An unknown error occurred' ), 'pluginsFound' => __( 'Number of plugins found: %d' ), 'noPluginsFound' => __( 'No plugins found. Try a different search.' ), diff --git a/tests/qunit/fixtures/updates.js b/tests/qunit/fixtures/updates.js index 8332039713..82a8311d60 100644 --- a/tests/qunit/fixtures/updates.js +++ b/tests/qunit/fixtures/updates.js @@ -30,7 +30,7 @@ window._wpUpdatesSettings = { 'themeInstallFailedLabel': '%s installation failed', 'installingMsg': 'Installing... please wait.', 'installedMsg': 'Installation completed successfully.', - 'importerInstalledMsg': 'Importer installed successfully. Activate plugin & run importer', + 'importerInstalledMsg': 'Importer installed successfully. Run importer', 'aysDelete': 'Are you sure you want to delete %s?', 'aysDeleteUninstall': 'Are you sure you want to delete %s and its data?', 'aysBulkDelete': 'Are you sure you want to delete the selected plugins and their data?', @@ -43,7 +43,7 @@ window._wpUpdatesSettings = { 'activateTheme': 'Activate', 'activatePluginLabel': 'Activate %s', 'activateThemeLabel': 'Activate %s', - 'activateImporter': 'Activate importer', + 'activateImporter': 'Run Importer', 'unknownError': 'An unknown error occurred', 'pluginsFound': 'Number of plugins found: %d', 'noPluginsFound': 'No plugins found. Try a different search.'