- http://www.rocq.net/yann/ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /** * Implementation of hook_help() */ function wordpress_import_help($section='') { $output = ''; switch ($section) { case "admin/help#wordpress_import": $output = '
'. t("This module imports a WXR file generated by Wordpress blog software into Drupal"). '
'; break; } return $output; } /** * Implementation of hook_menu() */ function wordpress_import_menu() { $items = array(); $access_config = array('administer site configuration'); $items['admin/content/wordpress_import'] = array( 'title' => t('Wordpress import'), 'description' => t('Import Wordpress WXR file'), 'page callback' => 'drupal_get_form', 'page arguments' => array('wordpress_import_form'), 'access arguments' => $access_config ); return $items; } /** * Implementation of hook_form() */ function wordpress_import_form($form_state) { if (!isset($form_state['storage']['step'])) { $form_state['storage']['step'] = 1; } switch ($form_state['storage']['step']) { // Step 1 : Upload form case 1: $form['informations'] = array( '#value' => t('This module will import a WXR file generated by Wordpress. You MUST make a backup copy of your Drupal Database before proceeding') ); $opts = array('Server (already on saved as files/import.xml)','File upload (be aware of server file size limits)'); // $opts = array('Server','File upload'); $form['sourceopts'] = array( '#type' => 'radios', '#options' => $opts, '#default_value' => '0', // 'Server' '#title' => t('Choose an upload source'), '#size' => 40 ); $form['upload'] = array( '#type' => 'file', '#title' => t('Upload your WXR file'), '#size' => 40 ); break; // Step 2 : Options setting case 2: if ($form_state['values']['sourceopts']==0) { // 'Server' $fdir = file_directory_path(); $form_state['storage']['file_path'] = $fdir . '/import.xml'; } $wordpress = wordpress_import_items($form_state['storage']['file_path']); $users = wordpress_import_get_users($wordpress); // Users mapping $form['users_map'] = array( '#title' => t('Users mapping'), '#type' => 'fieldset', '#description' => t('Map each wordpress user to a drupal user'), '#collapsible' => TRUE, '#tree' => TRUE ); foreach ($users as $users_value) { $form['users_map'][$users_value] = array( '#type' => 'select', '#title' => $users_value, '#options' => wordpress_import_drupal_users_list() ); } foreach (taxonomy_get_vocabularies() as $vocabulary) { $vocabularies[$vocabulary->id] = check_plain($vocabulary->name); } // Options $form['options'] = array( '#type' => 'fieldset', '#title' => t('Options'), '#collapsible' => TRUE ); // Blog content type $node_types = node_get_types(); if ($node_types['blog']) { $form['options']['blog_type'] = array( '#type' => 'select', '#title' => 'Import posts in content type', '#options' => array( 'blog' => t('Blog'), 'story' => t('Story') ) ); } $form['options']['alias'] = array( '#type' => 'checkbox', '#title' => 'Create path aliases', '#default_value' => 'true', '#description' => t('This option tries to preserve the path of the wordpress original posts. It is useful only if the url of your drupal site root is the same as the wordpress site (!root) and if clean urls are activated', array('!root' => $wordpress['link'])) ); break; case 3: $form['new_users'] = array('#tree' => TRUE); foreach ($form_state['storage']['users_map'] as $key => $value) { if ($value == 'create_new_user') { $form['new_users'][$key] = array('#type' => 'fieldset', '#title' => t('Wordpress user %user', array('%user' => $key))); $form['new_users'][$key]['name'] = array('#type' => 'textfield', '#title' => t('Username for Wordpress user %user', array('%user' => $key)), '#required' => TRUE, '#default_value' => $key); $form['new_users'][$key]['mail'] = array('#type' => 'textfield', '#title' => t('E-mail address for Wordpress user %user', array('%user' => $key)), '#required' => TRUE); } } break; case 4: $form['submit'] = array('#value' => t('The Wordpress blog has been successfully imported')); break; } // Form settings if ($form_state['storage']['step'] < 4) { $form['submit'] = array('#type' => 'submit', '#value' => t('Next')); $form_state['rebuild'] = TRUE; } // $form['#attributes']['enctype'] = 'multipart/form-data'; // $form['#submit'] = array('wordpress_import_form_submit_handler'); return $form; } /** * Implementation of hook_validate() */ function wordpress_import_form_validate($form, &$form_state) { switch ($form_state['storage']['step']) { case 1: // TODO: rjr - I don't see a way to validate this now that file_check_upload() is rolled into file save //if (!file_check_upload()) //{ // form_set_error('upload', t('You must provide a WXR file.')); //} if ($form_state['values']['sourceopts']==0) { // 'Server' // check to make sure the file is really there $fdir = file_directory_path(); if (!file_exists($fdir . '/import.xml')) { form_set_error('sourceopts', t('The file was not found at files/import.xml.')); } } break; case 3: if (isset($form_state['values']['new_users'])) { // TODO: not tested since I don't need it foreach ($form_state['values']['new_users'] as $key => $value) { // Check user name if ($error = user_validate_name($value['name'])) { form_set_error('new_users]['.$key.'][name', $error); } elseif (user_load(array('name' => $value['name']))) { form_set_error('new_users]['.$key.'][name', t('User !user already exists.', array('!user' => $value['name']))); } elseif (is_array($user['name']) && in_array(strtolower($value['name']), $user['name'])) { form_set_error('new_users]['.$key.'][name', t('Two users have the same name (!user).', array('!user' => $value['name']))); } // Check user mail if ($error = user_validate_mail($value['mail'])) { form_set_error('new_users]['.$key.'][mail', $error); } elseif (user_load(array('mail' => $value['mail']))) { form_set_error('new_users]['.$key.'][mail', t('User with mail !mail already exists.', array('!mail' => $value['mail']))); } elseif (is_array($user['mail']) && in_array(strtolower($value['mail']), $user['mail'])) { form_set_error('new_users]['.$key.'][mail', t('Two users have the same mail (!mail).', array('!mail' => $value['mail']))); } $user['name'][] = strtolower($value['name']); $user['mail'][] = strtolower($value['mail']); } } break; } } /** * Implementation of hook_submit() */ function wordpress_import_form_submit($form, &$form_state) { switch ($form_state['storage']['step']) { // Step 1 : upload file case 1: // TODO: rjr - this doesn't create the directory... it just fails if it doesn't exist $wordpress_path = file_create_path('wordpress'); $exists = file_check_directory($wordpress_path); $file_info = file_save_upload('upload',array(), $wordpress_path.'/import.xml', true); // TODO: rjr - if file_save_upload failed then $file_info is 0, handle it? $form_state['storage']['file_path'] = $file_info->filepath; // TODO: kludge - upload just doesn't work. $form_state['storage']['file_path'] = '/home/rob4/www/copper/htdocs/d6/sites/default/files/wordpress/import.xml'; break; // Step 2 : import blog case 2: $form_state['storage']['users_map'] = $form_state['values']['users_map']; $form_state['storage']['alias'] = $form_state['values']['alias']; $form_state['storage']['blog_type'] = $form_state['values']['blog_type']; break; case 3: if (isset($form_state['values']['new_users'])) { // TODO: not tested since I don't need it foreach ($form_state['values']['new_users'] as $key => $value) { $user = array('mail' => $value['mail'], 'pass' => user_password(), 'name' => $value['name'], 'status' => 1); $user = user_save('', $user); $form_state['storage']['users_map'][$key] = $user->uid; } } wordpress_import_import_blog($form_state['storage']); break; } $form_state['storage']['step'] = $form_state['storage']['step'] + 1; $form_state['rebuild'] = TRUE; } function wordpress_import_must_create_users($users_map) { return in_array('create_new_user', $users_map); } /** * Display Wordpress import form */ function wordpress_import_home() { $output = drupal_get_form('wordpress_import_form'); return $output; } /** * Import blog * @param array $params parameters */ function wordpress_import_import_blog($params) { if (!$params['blog_type']) { $params['blog_type'] = 'story'; } $tag_vocabulary = array( 'name' => t('Wordpress tag'), 'tags' => 1, 'nodes' => array('page' => 'page', $params['blog_type'] => $params['blog_type']) ); // TODO: this function is called twice to produce the same data. I suppose it's not a big deal but still... $wordpress = wordpress_import_items($params['file_path']); $wpcategories = wordpress_import_import_categories($wordpress, $params); if (is_array($wpcategories)) { $params = array_merge($params, wordpress_import_import_categories($wordpress, $params)); } $params['tags_vocabulary'] = wordpress_import_create_vocabulary('tag', $tag_vocabulary); wordpress_import_posts($wordpress, $params); // Clear the cache so an anonymous poster can see the node being added or updated. cache_clear_all(); } /** * Import categories * @param array $wordpress wordpress data * @return array categories mapping and taxonomy id */ function wordpress_import_import_categories($wordpress, $params) { // Create new taxonomy for wordpress categories $category_vocabulary_data = array( 'name' => t('Wordpress category'), 'hierarchy' => 2, 'multiple' => 1, 'nodes' => array('page' => 'page', $params['blog_type'] => $params['blog_type']) ); $category_vocabulary = wordpress_import_create_vocabulary('category', $category_vocabulary_data); // Import categories if (is_array($wordpress['categories'])) { foreach ($wordpress['categories'] as $key => $value) { $category_name = wordpress_import_get_tag($value, 'wp:cat_name'); $category_parent = wordpress_import_get_tag($value, 'wp:category_parent'); $category_term = array( 'name' => $category_name, 'vid' => $category_vocabulary ); if ($category_parent !== NULL && $category_parent !== '') { $category_term['parent'] = $category_mapping[$category_parent]; } taxonomy_save_term($category_term); // Save mapping between Wordpress and Drupal categories $category_mapping[$category_name] = $category_term['tid']; } return array ( 'categories_map' => $category_mapping, 'categories_vocabulary' => $category_vocabulary ); } } /** * Return vocabulary id of the $type provided or a new one if it doesn't exist * @return integer new taxonomy id */ function wordpress_import_create_vocabulary($type, $vocabulary_data) { // Check if a category for Wordpress already exists $vocabulary_id = variable_get('wordpress_import_'.$type, 0); if ($vocabulary_id) { $vocabulary = (array)taxonomy_vocabulary_load($vocabulary_id); } // Create vocabulary if it doesn't exist if (!$vocabulary) { $vocabulary_data['module'] = 'wordpress_import'; taxonomy_save_vocabulary($vocabulary_data); variable_set('wordpress_import_'.$type,$vocabulary_data['vid']); $vocabulary = $vocabulary_data; } return $vocabulary['vid']; } /** * Import posts and create clean urls if required * @param array $wordpress wordpress data * @param array $params parameters */ function wordpress_import_posts($wordpress, $params) { $params['format'] = wordpress_import_get_format(); foreach ($wordpress['posts'] as $post_value) { $post_info = wordpress_import_post($post_value, $params); if ($post_info && $params['alias']) { $link = wordpress_import_get_tag($post_value, 'link'); $link = substr($link,strlen($wordpress['link'])); // all wordpress urls end with '/', all drupal urls do not // this line removes the trailing slash so the url will work, but // it is a _different_ url - perhaps it's a good idea to recommend // a module like Global Redirect or an .htaccess hack so that old // links will still work. $link = rtrim($link,'/'); path_set_alias('node/'.$post_info['nid'], $link); } } } /** * Import a post * @param array $post post data * @param array $params parameters * @return array post infos */ function wordpress_import_post($post, $params) { $uid = $params['users_map'][wordpress_import_get_tag( $post, 'dc:creator' )]; // Don't import the post if the user hasn't been selected if(!ctype_digit($uid)) return FALSE; // Get post type : blog entry (post) or page // Posts are promoted in front page but not the pages $post_type = wordpress_import_get_tag($post,'wp:post_type'); $guess_post_type = false; switch ($post_type) { case 'post': $type = $params['blog_type']; $promote = '1'; break; case 'page': $type = 'page'; $promote = '0'; break; default: $guess_post_type = true; break; return; } if ($guess_post_type) { // in my case $post_type for all posts and pages was blank, maybe a bug in export? // alternate method of detecting $post_type $allmeta = wordpress_import_get_tag($post,'wp:postmeta'); $meta =''; $tagix = 1; // default to handling as a post $type = $params['blog_type']; do { $meta = wordpress_import_get_tag($allmeta,'wp:meta_key',$tagix); if ($meta == '_wp_page_template') { // if there's a page template then it's a page $type = 'page'; $promote = '0'; // if you want to add support for sorting out page templates then here you'll want to do something like // $page_template = wordpress_import_get_tag($allmeta,'wp:meta_value',$tagix); // and $page_template should get a value like 'my-page-template.php' break; } // TODO: my posts only have one meta_key and it's the template, if there are several then this might find them $tagix++; } while ($meta !== ''); } // Parsing categories preg_match_all('|