<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[22632] trunk/wp-admin: Pull the list of popular importers from WordPress.org.</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg > ul, #logmsg > ol { margin-left: 0; margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://core.trac.wordpress.org/changeset/22632">22632</a></dd>
<dt>Author</dt> <dd>nacin</dd>
<dt>Date</dt> <dd>2012-11-17 07:20:04 +0000 (Sat, 17 Nov 2012)</dd>
</dl>

<h3>Log Message</h3>
<pre>Pull the list of popular importers from WordPress.org.

These are the importers we suggest on import.php, prompting the user to
install the relevant plugin for the import they want to go through.

If the API is inaccessible, it falls back to a hard-coded list that should
be kept sync'd with the API with each major version of WordPress. This API
enables us to add new importers between releases, as they are completed or
if services gain quick adoption. As a last resort, we can also temporarily
disable importers that are broken (due to API changes, for example).

The importer currently returns English strings (which are then run through
translate() for existing strings), but the locale is passed to the API,
allowing us to ship translated strings if we wish to be adventurous.

props dllh for the assist.
fixes <a href="http://core.trac.wordpress.org/ticket/18977">#18977</a>.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkwpadminimportphp">trunk/wp-admin/import.php</a></li>
<li><a href="#trunkwpadminincludesimportphp">trunk/wp-admin/includes/import.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkwpadminimportphp"></a>
<div class="modfile"><h4>Modified: trunk/wp-admin/import.php (22631 => 22632)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/wp-admin/import.php        2012-11-17 06:58:29 UTC (rev 22631)
+++ trunk/wp-admin/import.php        2012-11-17 07:20:04 UTC (rev 22632)
</span><span class="lines">@@ -29,22 +29,19 @@
</span><span class="cx">         '&lt;p&gt;' . __('&lt;a href=&quot;http://wordpress.org/support/&quot; target=&quot;_blank&quot;&gt;Support Forums&lt;/a&gt;') . '&lt;/p&gt;'
</span><span class="cx"> );
</span><span class="cx"> 
</span><del>-$popular_importers = array();
-if ( current_user_can('install_plugins') )
-        $popular_importers = array(
-                'blogger' =&gt; array( __('Blogger'), __('Install the Blogger importer to import posts, comments, and users from a Blogger blog.'), 'install' ),
-                'wpcat2tag' =&gt; array(__('Categories and Tags Converter'), __('Install the category/tag converter to convert existing categories to tags or tags to categories, selectively.'), 'install', 'wp-cat2tag' ),
-                'livejournal' =&gt; array( __( 'LiveJournal' ), __( 'Install the LiveJournal importer to import posts from LiveJournal using their API.' ), 'install' ),
-                'movabletype' =&gt; array( __('Movable Type and TypePad'), __('Install the Movable Type importer to import posts and comments from a Movable Type or TypePad blog.'), 'install', 'mt' ),
-                'opml' =&gt; array( __('Blogroll'), __('Install the blogroll importer to import links in OPML format.'), 'install' ),
-                'rss' =&gt; array( __('RSS'), __('Install the RSS importer to import posts from an RSS feed.'), 'install' ),
-                'tumblr' =&gt; array( __('Tumblr'), __('Install the Tumblr importer to import posts &amp;amp; media from Tumblr using their API.'), 'install' ),
-                'wordpress' =&gt; array( 'WordPress', __('Install the WordPress importer to import posts, pages, comments, custom fields, categories, and tags from a WordPress export file.'), 'install' )
-        );
</del><ins>+if ( current_user_can( 'install_plugins' ) )
+        $popular_importers = wp_get_popular_importers();
+else
+        $popular_importers = array();
</ins><span class="cx"> 
</span><del>-if ( ! empty( $_GET['invalid'] ) &amp;&amp; !empty($popular_importers[$_GET['invalid']][3]) ) {
-        wp_redirect( admin_url('import.php?import=' . $popular_importers[$_GET['invalid']][3]) );
-        exit;
</del><ins>+// Detect and redirect invalid importers like 'movabletype', which is registered as 'mt'
+if ( ! empty( $_GET['invalid'] ) &amp;&amp; isset( $popular_importers[ $_GET['invalid'] ] ) ) {
+        $importer_id = $popular_importers[ $_GET['invalid'] ]['importer-id'];
+        if ( $importer_id != $_GET['invalid'] ) { // Prevent redirect loops.
+                wp_redirect( admin_url( 'admin.php?import=' . $importer_id ) );
+                exit;
+        }
+        unset( $importer_id );
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> add_thickbox();
</span><span class="lines">@@ -68,28 +65,26 @@
</span><span class="cx"> 
</span><span class="cx"> // If a popular importer is not registered, create a dummy registration that links to the plugin installer.
</span><span class="cx"> foreach ( $popular_importers as $pop_importer =&gt; $pop_data ) {
</span><del>-        if ( isset( $importers[$pop_importer] ) )
</del><ins>+        if ( isset( $importers[ $pop_importer ] ) )
</ins><span class="cx">                 continue;
</span><del>-        if ( isset( $pop_data[3] ) &amp;&amp; isset( $importers[ $pop_data[3] ] ) )
</del><ins>+        if ( isset( $importers[ $pop_data['importer-id'] ] ) )
</ins><span class="cx">                 continue;
</span><del>-
-        $importers[$pop_importer] = $popular_importers[$pop_importer];
</del><ins>+        $importers[ $pop_data['importer-id'] ] = array( $pop_data['name'], $pop_data['description'], 'install' =&gt; $pop_data['plugin-slug'] );
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-if ( empty($importers) ) {
-        echo '&lt;p&gt;'.__('No importers are available.').'&lt;/p&gt;'; // TODO: make more helpful
</del><ins>+if ( empty( $importers ) ) {
+        echo '&lt;p&gt;' . __('No importers are available.') . '&lt;/p&gt;'; // TODO: make more helpful
</ins><span class="cx"> } else {
</span><del>-        uasort($importers, create_function('$a, $b', 'return strcmp($a[0], $b[0]);'));
</del><ins>+        uasort($importers, create_function('$a, $b', 'return strnatcasecmp($a[0], $b[0]);'));
</ins><span class="cx"> ?&gt;
</span><span class="cx"> &lt;table class=&quot;widefat importers&quot; cellspacing=&quot;0&quot;&gt;
</span><span class="cx"> 
</span><span class="cx"> &lt;?php
</span><del>-        $style = '';
-        foreach ($importers as $id =&gt; $data) {
-                $style = ('class=&quot;alternate&quot;' == $style || 'class=&quot;alternate active&quot;' == $style) ? '' : 'alternate';
</del><ins>+        $alt = '';
+        foreach ($importers as $importer_id =&gt; $data) {
</ins><span class="cx">                 $action = '';
</span><del>-                if ( 'install' == $data[2] ) {
-                        $plugin_slug = $id . '-importer';
</del><ins>+                if ( isset( $data['install'] ) ) {
+                        $plugin_slug = $data['install'];
</ins><span class="cx">                         if ( file_exists( WP_PLUGIN_DIR . '/' . $plugin_slug ) ) {
</span><span class="cx">                                 // Looks like Importer is installed, But not active
</span><span class="cx">                                 $plugins = get_plugins( '/' . $plugin_slug );
</span><span class="lines">@@ -111,13 +106,12 @@
</span><span class="cx">                                 }
</span><span class="cx">                         }
</span><span class="cx">                 } else {
</span><del>-                        $action = &quot;&lt;a href='&quot; . esc_url(&quot;admin.php?import=$id&quot;) . &quot;' title='&quot; . esc_attr( wptexturize(strip_tags($data[1])) ) .&quot;'&gt;{$data[0]}&lt;/a&gt;&quot;;
</del><ins>+                        $action = &quot;&lt;a href='&quot; . esc_url( &quot;admin.php?import=$importer_id&quot; ) . &quot;' title='&quot; . esc_attr( wptexturize( strip_tags( $data[1] ) ) ) .&quot;'&gt;{$data[0]}&lt;/a&gt;&quot;;
</ins><span class="cx">                 }
</span><span class="cx"> 
</span><del>-                if ($style != '')
-                        $style = 'class=&quot;'.$style.'&quot;';
</del><ins>+                $alt = $alt ? '' : ' class=&quot;alternate&quot;';
</ins><span class="cx">                 echo &quot;
</span><del>-                        &lt;tr $style&gt;
</del><ins>+                        &lt;tr$alt&gt;
</ins><span class="cx">                                 &lt;td class='import-system row-title'&gt;$action&lt;/td&gt;
</span><span class="cx">                                 &lt;td class='desc'&gt;{$data[1]}&lt;/td&gt;
</span><span class="cx">                         &lt;/tr&gt;&quot;;
</span></span></pre></div>
<a id="trunkwpadminincludesimportphp"></a>
<div class="modfile"><h4>Modified: trunk/wp-admin/includes/import.php (22631 => 22632)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/wp-admin/includes/import.php        2012-11-17 06:58:29 UTC (rev 22631)
+++ trunk/wp-admin/includes/import.php        2012-11-17 07:20:04 UTC (rev 22632)
</span><span class="lines">@@ -93,3 +93,93 @@
</span><span class="cx"> 
</span><span class="cx">         return array( 'file' =&gt; $file, 'id' =&gt; $id );
</span><span class="cx"> }
</span><ins>+
+/**
+ * Returns a list from WordPress.org of popular importer plugins.
+ *
+ * @since 3.5.0
+ *
+ * @return array Importers with metadata for each.
+ */
+function wp_get_popular_importers() {
+        include ABSPATH . WPINC . '/version.php'; // include an unmodified $wp_version
+
+        $locale = get_locale();
+        $popular_importers = get_site_transient( 'popular_importers_' . $locale );
+
+        if ( ! $popular_importers ) {
+                $url = add_query_arg( 'locale', get_locale(), 'http://api.wordpress.org/core/importers/1.0/' );
+                $options = array( 'user-agent' =&gt; 'WordPress/' . $wp_version . '; ' . home_url() );
+                $popular_importers = maybe_unserialize( wp_remote_retrieve_body( wp_remote_get( $url, $options ) ) );
+
+                if ( is_array( $popular_importers ) )
+                        set_site_transient( 'popular_importers_' . $locale, $popular_importers, 2 * DAY_IN_SECONDS );
+                else
+                        $popular_importers = false;
+        }
+
+        if ( is_array( $popular_importers ) ) {
+                // If the data was received as translated, return it as-is.
+                if ( $popular_importers['translated'] )
+                        return $popular_importers['importers'];
+
+                foreach ( $popular_importers['importers'] as &amp;$importer ) {
+                        $importer['description'] = translate( $importer['description'] );
+                        if ( $importer['name'] != 'WordPress' )
+                                $importer['name'] = translate( $importer['name'] );
+                }
+                return $popular_importers['importers'];
+        }
+
+        return array(
+                // slug =&gt; name, description, plugin slug, and register_importer() slug
+                'blogger' =&gt; array(
+                        'name' =&gt; __( 'Blogger' ),
+                        'description' =&gt; __( 'Install the Blogger importer to import posts, comments, and users from a Blogger blog.' ),
+                        'plugin-slug' =&gt; 'blogger-importer',
+                        'importer-id' =&gt; 'blogger',
+                ),
+                'wpcat2tag' =&gt; array(
+                        'name' =&gt; __( 'Categories and Tags Converter' ),
+                        'description' =&gt; __( 'Install the category/tag converter to convert existing categories to tags or tags to categories, selectively.' ),
+                        'plugin-slug' =&gt; 'wpcat2tag-importer',
+                        'importer-id' =&gt; 'wp-cat2tag',
+                ),
+                'livejournal' =&gt; array(
+                        'name' =&gt; __( 'LiveJournal' ),
+                        'description' =&gt; __( 'Install the LiveJournal importer to import posts from LiveJournal using their API.' ),
+                        'plugin-slug' =&gt; 'livejournal-importer',
+                        'importer-id' =&gt; 'livejournal',
+                ),
+                'movabletype' =&gt; array(
+                        'name' =&gt; __( 'Movable Type and TypePad' ),
+                        'description' =&gt; __( 'Install the Movable Type importer to import posts and comments from a Movable Type or TypePad blog.' ),
+                        'plugin-slug' =&gt; 'movabletype-importer',
+                        'importer-id' =&gt; 'mt',
+                ),
+                'opml' =&gt; array(
+                        'name' =&gt; __( 'Blogroll' ),
+                        'description' =&gt; __( 'Install the blogroll importer to import links in OPML format.' ),
+                        'plugin-slug' =&gt; 'opml-importer',
+                        'importer-id' =&gt; 'opml',
+                ),
+                'rss' =&gt; array(
+                        'name' =&gt; __( 'RSS' ),
+                        'description' =&gt; __( 'Install the RSS importer to import posts from an RSS feed.' ),
+                        'plugin-slug' =&gt; 'rss-importer',
+                        'importer-id' =&gt; 'rss',
+                ),
+                'tumblr' =&gt; array(
+                        'name' =&gt; __( 'Tumblr' ),
+                        'description' =&gt; __( 'Install the Tumblr importer to import posts &amp;amp; media from Tumblr using their API.' ),
+                        'plugin-slug' =&gt; 'tumblr-importer',
+                        'importer-id' =&gt; 'tumblr',
+                ),
+                'wordpress' =&gt; array(
+                        'name' =&gt; 'WordPress',
+                        'description' =&gt; __( 'Install the WordPress importer to import posts, pages, comments, custom fields, categories, and tags from a WordPress export file.' ),
+                        'plugin-slug' =&gt; 'wordpress-importer',
+                        'importer-id' =&gt; 'wordpress',
+                ),
+        );
+}
</ins></span></pre>
</div>
</div>

</body>
</html>