University Marketing & Communications

July 18, 2012

Write a custom WordPress Importer, part 2

By Chris Heiland

This was originally posted on Chris Heiland’s staff blog while he was a member of the Web Team. Chris migrated this post to the Web Team blog before he left because we thought the content still had value to the UW community.


In Part 1 it was all about the WP Importer class, now that we are done with the basics we can move on to actually writing some importing with outlining the functions we’ll need in order to actually do something. Now let’s take that and actually do something useful with the class and add some methods that WordPress can take advantage of.

In an importer class the minimal number of useful methods to make a post are:

  • dispatch()
  • import()
  • import_posts()
  • process_posts()
  • header()
  • footer()
  • greet()
  • custom_importer_init()

There are others depending on your custom data fields or structure but those are the necessary ones to get off the ground. Some others to consider are:

  • import_author()
  • import_categories()
  • import_images()
  • import_tags()

In theory you could use import_posts() instead of additionally using the process_posts() function but there’s good reason to separate them out. Following this specific process is not mandatory but it’s what the WordPress Importer uses. Also, the WordPress Importer assumes you will be uploading a file to run through and grab all your data from. My data existed on the filesystem as a sqlite3 db, so it’s possible to get around it, but that’s probably not the typical use case.

To give an overview of the process, once the importer is registered then the dispatch() function is called. Once in that function, the import() function calls the import_posts() which takes the custom data source (xml,db) and loads up the $this->posts property.

Then, once all the posts data is loaded (author,categories,tags,images), the process_posts() function is run to actually load all the information into the WordPress db. It’s a fairly straightforward workflow but it helps to have some code as a starting point. Having said that, here is some code. As with before, fill in your importer where where I have {{ Custom Importer Name }} and custom.

/**
   * Registered callback function for the Custom Importer
   *
   * Manages the separate stages of the import process
   */
  function dispatch() {
    $this->header();
    // This all from the WordPress Importer plugin, handles most cases
    $step = empty( $_GET['step'] ) ? 0 : (int) $_GET['step'];
    switch ( $step ) {
      case 0:
        $this->greet();
        break;
      case 1:
        check_admin_referer( 'import-upload' );
        if ( $this->handle_upload() )
          $this->import_options();
        break;
      case 2:
        check_admin_referer( 'import-custom' );
        $this->fetch_attachments = ( ! empty( $_POST['fetch_attachments'] ) && $this->allow_fetch_attachments() );
        $this->id = (int) $_POST['import_id'];
        // Provides the actual file upload form
        $file = get_attached_file( $this->id );
        set_time_limit(0);
        $this->import( $file );
        break;
    }
    $this->footer();
  }

  /**
   * The main controller for the actual import stage. Contains all the import steps.
   *
   * @param none
   * @return none
   */
  function import() {
    $this->import_posts();
    $this->process_posts();
    echo '<h3>';
    printf(__('All done. Celebrate!','custom-importer'), get_option('home'));
    echo '</h3>';
  }

  /**
   * Imports posts and loads $this->posts
   *
   * @uses $wpdb
   *
   * @param none
   * @return none
   */
  function import_posts() {
    global $wpdb;
    // $arrArticles contains all of your custom content
    $index = 0;
    while ($objArticle = $arrArticles)  {
      $post['post_title'] = $wpdb->escape($objArticle->title);
      $post['post_excerpt'] = $wpdb->escape($objArticle->desc);
      $post['category'] = $this->import_category($objArticle->cat);
      $post['post_author'] = $this->import_author($objArticle->author);
      # ... and so on...
      $this->posts[$index] = $post;
      $index++;
  }

  /**
   * Imports authors
   *
   * @uses $wpdb
   *
   * @param none
   * @return bool|int The user's ID on success, and id of admin (1) on failure
   */
  function import_author() { 
    global $wpdb;
    while ($objAuthor = $arrAuthors) {
      $user_data = array(
        'user_login'       => sanitize_user($objAuthor->login, true),
        'user_pass'        => wp_generate_password(),
        'user_url'         => '',
        'user_email'       => $wpdb->escape($objAuthor->email),
        'display_name'     => $wpdb->escape($objAuthor->full_name),
        'first_name'       => $wpdb->escape($objAuthor->first_name),
        'last_name'        => $wpdb->escape($objAuthor->last_name),
        'description'      => '',
      );

      // Quick Check for an existing user
      $user = $this->authors[$user_data['user_login']];
      if ($user)
        return $user->ID;
      $user = get_user_by('email', $user_data['user_email']);
      if ($user)
        return $user->ID;

      // Go ahead and insert
      $user_id = wp_insert_user( $user_data );

      if ( ! is_wp_error( $user_id ) ) {
        $this->authors[$user_data['user_login']] = get_userdata($user_id);
        return trim($user_id);
      } else {
        if ($user_id->get_error_code() == 'existing_user_login') {
          // If we are here, user already exists, just need to look them up
          $user = get_user_by('email', $user_data['user_email']);
          return trim($user->ID);
        } else {
          printf( __( 'Failed to create new user for %s. Their posts will be attributed to the admin.', 'custom-importer' ), esc_html($user_data['display_name']) );
          if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG )
            echo ' ' . $user_id->get_error_message().' ('.$user_id->get_error_code().')';
            echo '<br />';
        }
      }
    }
  }

  /**
   * Takes imported posts and actually inserts into wordpress
   *
   * @param none
   * @return string return WP_Object if can't post
   */
  function process_posts() {
    foreach ($this->posts as $post) {
      echo "<li>".__('Importing post...', 'custom-importer');
      extract($post);

      if ($post_id = post_exists($post_title, $post_content, $post_date)) {
        _e('Post already imported', 'custom-importer');
      } else {
        $post_id = wp_insert_post($post);
        if ( is_wp_error( $post_id ) )
          return $post_id;
        if (!$post_id) {
          _e('Couldn’t get post ID', 'custom-importer');
          return;
        } 
        wp_create_categories(array('Category1','Category2'), $post_id);
        _e('Done!', 'custom-importer');
      }
    echo '</li>';
  }

}
// Register the custom importer we've created.
$custom_import = new {{ Custom Importer Name}}_Import();

register_importer('custom', __('{{ Custom Importer Name}}', 'custom-importer'), __('Import posts custom source.', 'custom-importer'), array ($custom_import, 'dispatch'));

} // class_exists( 'WP_Importer' )

function custom_importer_init() {
load_plugin_textdomain( 'custom-importer', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
}
add_action( 'init', 'custom_importer_init' );

That’s it! Hopefully you found this helpful and will be able to migrate your content into WordPress with ease.