7 * @author Thomas Quinot
8 * @link http://thomas.quinot.org/
12 Add These Functions to make our lives easier
15 if(!function_exists('get_comment_count'))
18 * Get the comment count for posts.
21 * @subpackage Dotclear_Import
23 * @param int $post_ID Post ID
26 function get_comment_count($post_ID)
29 return $wpdb->get_var( $wpdb->prepare("SELECT count(*) FROM $wpdb->comments WHERE comment_post_ID = %d", $post_ID) );
33 if(!function_exists('link_exists'))
36 * Check whether link already exists.
39 * @subpackage Dotclear_Import
41 * @param string $linkname
44 function link_exists($linkname)
47 return $wpdb->get_var( $wpdb->prepare("SELECT link_id FROM $wpdb->links WHERE link_name = %s", $linkname) );
53 Taken from http://www.php.net/manual/fr/function.mb-detect-encoding.php#50087
56 // utf8 encoding validation developed based on Wikipedia entry at:
57 // http://en.wikipedia.org/wiki/UTF-8
59 // Implemented as a recursive descent parser based on a simple state machine
60 // copyright 2005 Maarten Meijer
62 // This cries out for a C-implementation to be included in PHP core
67 * @subpackage Dotclear_Import
72 function valid_1byte($char) {
73 if(!is_int($char)) return false;
74 return ($char & 0x80) == 0x00;
79 * @subpackage Dotclear_Import
84 function valid_2byte($char) {
85 if(!is_int($char)) return false;
86 return ($char & 0xE0) == 0xC0;
91 * @subpackage Dotclear_Import
96 function valid_3byte($char) {
97 if(!is_int($char)) return false;
98 return ($char & 0xF0) == 0xE0;
103 * @subpackage Dotclear_Import
105 * @param string $char
108 function valid_4byte($char) {
109 if(!is_int($char)) return false;
110 return ($char & 0xF8) == 0xF0;
115 * @subpackage Dotclear_Import
117 * @param string $char
120 function valid_nextbyte($char) {
121 if(!is_int($char)) return false;
122 return ($char & 0xC0) == 0x80;
127 * @subpackage Dotclear_Import
129 * @param string $string
132 function valid_utf8($string) {
133 $len = strlen($string);
136 $char = ord(substr($string, $i++, 1));
137 if(valid_1byte($char)) { // continue
139 } else if(valid_2byte($char)) { // check 1 byte
140 if(!valid_nextbyte(ord(substr($string, $i++, 1))))
142 } else if(valid_3byte($char)) { // check 2 bytes
143 if(!valid_nextbyte(ord(substr($string, $i++, 1))))
145 if(!valid_nextbyte(ord(substr($string, $i++, 1))))
147 } else if(valid_4byte($char)) { // check 3 bytes
148 if(!valid_nextbyte(ord(substr($string, $i++, 1))))
150 if(!valid_nextbyte(ord(substr($string, $i++, 1))))
152 if(!valid_nextbyte(ord(substr($string, $i++, 1))))
161 * @subpackage Dotclear_Import
167 if (valid_utf8 ($s)) {
170 return iconv(get_option ("dccharset"),"UTF-8",$s);
176 * @subpackage Dotclear_Import
181 function textconv ($s) {
182 return csc (preg_replace ('|(?<!<br />)\s*\n|', ' ', $s));
186 * Dotclear Importer class
188 * Will process the WordPress eXtended RSS files that you upload from the export
192 * @subpackage Importer
196 class Dotclear_Import {
200 echo '<div class="wrap">';
202 echo '<h2>'.__('Import DotClear').'</h2>';
203 echo '<p>'.__('Steps may take a few minutes depending on the size of your database. Please be patient.').'</p>';
213 echo '<div class="narrow"><p>'.__('Howdy! This importer allows you to extract posts from a DotClear database into your blog. Mileage may vary.').'</p>';
214 echo '<p>'.__('Your DotClear Configuration settings are as follows:').'</p>';
215 echo '<form action="admin.php?import=dotclear&step=1" method="post">';
216 wp_nonce_field('import-dotclear');
218 echo '<p class="submit"><input type="submit" name="submit" class="button" value="'.attribute_escape(__('Import Categories')).'" /></p>';
219 echo '</form></div>';
222 function get_dc_cats()
225 // General Housekeeping
226 $dcdb = new wpdb(get_option('dcuser'), get_option('dcpass'), get_option('dcname'), get_option('dchost'));
227 set_magic_quotes_runtime(0);
228 $dbprefix = get_option('dcdbprefix');
231 return $dcdb->get_results('SELECT * FROM '.$dbprefix.'categorie', ARRAY_A);
234 function get_dc_users()
237 // General Housekeeping
238 $dcdb = new wpdb(get_option('dcuser'), get_option('dcpass'), get_option('dcname'), get_option('dchost'));
239 set_magic_quotes_runtime(0);
240 $dbprefix = get_option('dcdbprefix');
244 return $dcdb->get_results('SELECT * FROM '.$dbprefix.'user', ARRAY_A);
247 function get_dc_posts()
249 // General Housekeeping
250 $dcdb = new wpdb(get_option('dcuser'), get_option('dcpass'), get_option('dcname'), get_option('dchost'));
251 set_magic_quotes_runtime(0);
252 $dbprefix = get_option('dcdbprefix');
255 return $dcdb->get_results('SELECT '.$dbprefix.'post.*, '.$dbprefix.'categorie.cat_libelle_url AS post_cat_name
256 FROM '.$dbprefix.'post INNER JOIN '.$dbprefix.'categorie
257 ON '.$dbprefix.'post.cat_id = '.$dbprefix.'categorie.cat_id', ARRAY_A);
260 function get_dc_comments()
263 // General Housekeeping
264 $dcdb = new wpdb(get_option('dcuser'), get_option('dcpass'), get_option('dcname'), get_option('dchost'));
265 set_magic_quotes_runtime(0);
266 $dbprefix = get_option('dcdbprefix');
269 return $dcdb->get_results('SELECT * FROM '.$dbprefix.'comment', ARRAY_A);
272 function get_dc_links()
274 //General Housekeeping
275 $dcdb = new wpdb(get_option('dcuser'), get_option('dcpass'), get_option('dcname'), get_option('dchost'));
276 set_magic_quotes_runtime(0);
277 $dbprefix = get_option('dcdbprefix');
279 return $dcdb->get_results('SELECT * FROM '.$dbprefix.'link ORDER BY position', ARRAY_A);
282 function cat2wp($categories='')
284 // General Housekeeping
287 $dccat2wpcat = array();
289 if(is_array($categories))
291 echo '<p>'.__('Importing Categories...').'<br /><br /></p>';
292 foreach ($categories as $category)
297 // Make Nice Variables
298 $name = $wpdb->escape($cat_libelle_url);
299 $title = $wpdb->escape(csc ($cat_libelle));
300 $desc = $wpdb->escape(csc ($cat_desc));
302 if($cinfo = category_exists($name))
304 $ret_id = wp_insert_category(array('cat_ID' => $cinfo, 'category_nicename' => $name, 'cat_name' => $title, 'category_description' => $desc));
308 $ret_id = wp_insert_category(array('category_nicename' => $name, 'cat_name' => $title, 'category_description' => $desc));
310 $dccat2wpcat[$id] = $ret_id;
313 // Store category translation for future use
314 add_option('dccat2wpcat',$dccat2wpcat);
315 echo '<p>'.sprintf(__ngettext('Done! <strong>%1$s</strong> category imported.', 'Done! <strong>%1$s</strong> categories imported.', $count), $count).'<br /><br /></p>';
318 echo __('No Categories to Import!');
322 function users2wp($users='')
324 // General Housekeeping
327 $dcid2wpid = array();
332 echo '<p>'.__('Importing Users...').'<br /><br /></p>';
333 foreach($users as $user)
338 // Make Nice Variables
339 $name = $wpdb->escape(csc ($name));
340 $RealName = $wpdb->escape(csc ($user_pseudo));
342 if($uinfo = get_userdatabylogin($name))
345 $ret_id = wp_insert_user(array(
347 'user_login' => $user_id,
348 'user_nicename' => $Realname,
349 'user_email' => $user_email,
350 'user_url' => 'http://',
351 'display_name' => $Realname)
356 $ret_id = wp_insert_user(array(
357 'user_login' => $user_id,
358 'user_nicename' => csc ($user_pseudo),
359 'user_email' => $user_email,
360 'user_url' => 'http://',
361 'display_name' => $Realname)
364 $dcid2wpid[$user_id] = $ret_id;
366 // Set DotClear-to-WordPress permissions translation
368 // Update Usermeta Data
369 $user = new WP_User($ret_id);
370 $wp_perms = $user_level + 1;
371 if(10 == $wp_perms) { $user->set_role('administrator'); }
372 else if(9 == $wp_perms) { $user->set_role('editor'); }
373 else if(5 <= $wp_perms) { $user->set_role('editor'); }
374 else if(4 <= $wp_perms) { $user->set_role('author'); }
375 else if(3 <= $wp_perms) { $user->set_role('contributor'); }
376 else if(2 <= $wp_perms) { $user->set_role('contributor'); }
377 else { $user->set_role('subscriber'); }
379 update_usermeta( $ret_id, 'wp_user_level', $wp_perms);
380 update_usermeta( $ret_id, 'rich_editing', 'false');
381 update_usermeta( $ret_id, 'first_name', csc ($user_prenom));
382 update_usermeta( $ret_id, 'last_name', csc ($user_nom));
383 }// End foreach($users as $user)
385 // Store id translation array for future use
386 add_option('dcid2wpid',$dcid2wpid);
389 echo '<p>'.sprintf(__('Done! <strong>%1$s</strong> users imported.'), $count).'<br /><br /></p>';
391 }// End if(is_array($users)
393 echo __('No Users to Import!');
396 }// End function user2wp()
398 function posts2wp($posts='')
400 // General Housekeeping
403 $dcposts2wpposts = array();
409 echo '<p>'.__('Importing Posts...').'<br /><br /></p>';
410 foreach($posts as $post)
415 // Set DotClear-to-WordPress status translation
416 $stattrans = array(0 => 'draft', 1 => 'publish');
417 $comment_status_map = array (0 => 'closed', 1 => 'open');
419 //Can we do this more efficiently?
420 $uinfo = ( get_userdatabylogin( $user_id ) ) ? get_userdatabylogin( $user_id ) : 1;
421 $authorid = ( is_object( $uinfo ) ) ? $uinfo->ID : $uinfo ;
423 $Title = $wpdb->escape(csc ($post_titre));
424 $post_content = textconv ($post_content);
426 if ($post_chapo != "") {
427 $post_excerpt = textconv ($post_chapo);
428 $post_content = $post_excerpt ."\n<!--more-->\n".$post_content;
430 $post_excerpt = $wpdb->escape ($post_excerpt);
431 $post_content = $wpdb->escape ($post_content);
432 $post_status = $stattrans[$post_pub];
434 // Import Post data into WordPress
436 if($pinfo = post_exists($Title,$post_content))
438 $ret_id = wp_insert_post(array(
440 'post_author' => $authorid,
441 'post_date' => $post_dt,
442 'post_date_gmt' => $post_dt,
443 'post_modified' => $post_upddt,
444 'post_modified_gmt' => $post_upddt,
445 'post_title' => $Title,
446 'post_content' => $post_content,
447 'post_excerpt' => $post_excerpt,
448 'post_status' => $post_status,
449 'post_name' => $post_titre_url,
450 'comment_status' => $comment_status_map[$post_open_comment],
451 'ping_status' => $comment_status_map[$post_open_tb],
452 'comment_count' => $post_nb_comment + $post_nb_trackback)
454 if ( is_wp_error( $ret_id ) )
459 $ret_id = wp_insert_post(array(
460 'post_author' => $authorid,
461 'post_date' => $post_dt,
462 'post_date_gmt' => $post_dt,
463 'post_modified' => $post_modified_gmt,
464 'post_modified_gmt' => $post_modified_gmt,
465 'post_title' => $Title,
466 'post_content' => $post_content,
467 'post_excerpt' => $post_excerpt,
468 'post_status' => $post_status,
469 'post_name' => $post_titre_url,
470 'comment_status' => $comment_status_map[$post_open_comment],
471 'ping_status' => $comment_status_map[$post_open_tb],
472 'comment_count' => $post_nb_comment + $post_nb_trackback)
474 if ( is_wp_error( $ret_id ) )
477 $dcposts2wpposts[$post_id] = $ret_id;
479 // Make Post-to-Category associations
481 $category1 = get_category_by_slug($post_cat_name);
482 $category1 = $category1->term_id;
484 if($cat1 = $category1) { $cats[1] = $cat1; }
486 if(!empty($cats)) { wp_set_post_categories($ret_id, $cats); }
489 // Store ID translation for later use
490 add_option('dcposts2wpposts',$dcposts2wpposts);
492 echo '<p>'.sprintf(__('Done! <strong>%1$s</strong> posts imported.'), $count).'<br /><br /></p>';
496 function comments2wp($comments='')
498 // General Housekeeping
501 $dccm2wpcm = array();
502 $postarr = get_option('dcposts2wpposts');
505 if(is_array($comments))
507 echo '<p>'.__('Importing Comments...').'<br /><br /></p>';
508 foreach($comments as $comment)
514 $comment_ID = (int) ltrim($comment_id, '0');
515 $comment_post_ID = (int) $postarr[$post_id];
516 $comment_approved = "$comment_pub";
517 $name = $wpdb->escape(csc ($comment_auteur));
518 $email = $wpdb->escape($comment_email);
519 $web = "http://".$wpdb->escape($comment_site);
520 $message = $wpdb->escape(textconv ($comment_content));
522 if($cinfo = comment_exists($name, $comment_dt))
525 $ret_id = wp_update_comment(array(
526 'comment_ID' => $cinfo,
527 'comment_post_ID' => $comment_post_ID,
528 'comment_author' => $name,
529 'comment_author_email' => $email,
530 'comment_author_url' => $web,
531 'comment_author_IP' => $comment_ip,
532 'comment_date' => $comment_dt,
533 'comment_date_gmt' => $comment_dt,
534 'comment_content' => $message,
535 'comment_approved' => $comment_approved)
541 $ret_id = wp_insert_comment(array(
542 'comment_post_ID' => $comment_post_ID,
543 'comment_author' => $name,
544 'comment_author_email' => $email,
545 'comment_author_url' => $web,
546 'comment_author_IP' => $comment_ip,
547 'comment_date' => $comment_dt,
548 'comment_date_gmt' => $comment_dt,
549 'comment_content' => $message,
550 'comment_approved' => $comment_approved)
553 $dccm2wpcm[$comment_ID] = $ret_id;
555 // Store Comment ID translation for future use
556 add_option('dccm2wpcm', $dccm2wpcm);
558 // Associate newly formed categories with posts
559 get_comment_count($ret_id);
562 echo '<p>'.sprintf(__('Done! <strong>%1$s</strong> comments imported.'), $count).'<br /><br /></p>';
565 echo __('No Comments to Import!');
569 function links2wp($links='')
571 // General Housekeeping
575 // Deal with the links
578 echo '<p>'.__('Importing Links...').'<br /><br /></p>';
579 foreach($links as $link)
585 if ($cinfo = is_term(csc ($title), 'link_category')) {
586 $category = $cinfo['term_id'];
588 $category = wp_insert_term($wpdb->escape (csc ($title)), 'link_category');
589 $category = $category['term_id'];
592 $linkname = $wpdb->escape(csc ($label));
593 $description = $wpdb->escape(csc ($title));
595 if($linfo = link_exists($linkname)) {
596 $ret_id = wp_insert_link(array(
599 'link_name' => $linkname,
600 'link_category' => $category,
601 'link_description' => $description)
604 $ret_id = wp_insert_link(array(
606 'link_name' => $linkname,
607 'link_category' => $category,
608 'link_description' => $description)
611 $dclinks2wplinks[$link_id] = $ret_id;
614 add_option('dclinks2wplinks',$dclinks2wplinks);
616 printf(__ngettext('Done! <strong>%s</strong> link or link category imported.', 'Done! <strong>%s</strong> links or link categories imported.', $count), $count);
617 echo '<br /><br /></p>';
620 echo __('No Links to Import!');
624 function import_categories()
627 $cats = $this->get_dc_cats();
628 $this->cat2wp($cats);
629 add_option('dc_cats', $cats);
633 echo '<form action="admin.php?import=dotclear&step=2" method="post">';
634 wp_nonce_field('import-dotclear');
635 printf('<p class="submit"><input type="submit" name="submit" class="button" value="%s" /></p>', attribute_escape(__('Import Users')));
640 function import_users()
643 $users = $this->get_dc_users();
644 $this->users2wp($users);
646 echo '<form action="admin.php?import=dotclear&step=3" method="post">';
647 wp_nonce_field('import-dotclear');
648 printf('<p class="submit"><input type="submit" name="submit" class="button" value="%s" /></p>', attribute_escape(__('Import Posts')));
652 function import_posts()
655 $posts = $this->get_dc_posts();
656 $result = $this->posts2wp($posts);
657 if ( is_wp_error( $result ) )
660 echo '<form action="admin.php?import=dotclear&step=4" method="post">';
661 wp_nonce_field('import-dotclear');
662 printf('<p class="submit"><input type="submit" name="submit" class="button" value="%s" /></p>', attribute_escape(__('Import Comments')));
666 function import_comments()
669 $comments = $this->get_dc_comments();
670 $this->comments2wp($comments);
672 echo '<form action="admin.php?import=dotclear&step=5" method="post">';
673 wp_nonce_field('import-dotclear');
674 printf('<p class="submit"><input type="submit" name="submit" class="button" value="%s" /></p>', attribute_escape(__('Import Links')));
678 function import_links()
681 $links = $this->get_dc_links();
682 $this->links2wp($links);
683 add_option('dc_links', $links);
685 echo '<form action="admin.php?import=dotclear&step=6" method="post">';
686 wp_nonce_field('import-dotclear');
687 printf('<p class="submit"><input type="submit" name="submit" class="button" value="%s" /></p>', attribute_escape(__('Finish')));
691 function cleanup_dcimport()
693 delete_option('dcdbprefix');
694 delete_option('dc_cats');
695 delete_option('dcid2wpid');
696 delete_option('dccat2wpcat');
697 delete_option('dcposts2wpposts');
698 delete_option('dccm2wpcm');
699 delete_option('dclinks2wplinks');
700 delete_option('dcuser');
701 delete_option('dcpass');
702 delete_option('dcname');
703 delete_option('dchost');
704 delete_option('dccharset');
705 do_action('import_done', 'dotclear');
711 echo '<p>'.__('Welcome to WordPress. We hope (and expect!) that you will find this platform incredibly rewarding! As a new WordPress user coming from DotClear, there are some things that we would like to point out. Hopefully, they will help your transition go as smoothly as possible.').'</p>';
712 echo '<h3>'.__('Users').'</h3>';
713 echo '<p>'.sprintf(__('You have already setup WordPress and have been assigned an administrative login and password. Forget it. You didn\'t have that login in DotClear, why should you have it here? Instead we have taken care to import all of your users into our system. Unfortunately there is one downside. Because both WordPress and DotClear uses a strong encryption hash with passwords, it is impossible to decrypt it and we are forced to assign temporary passwords to all your users. <strong>Every user has the same username, but their passwords are reset to password123.</strong> So <a href="%1$s">Login</a> and change it.'), '/wp-login.php').'</p>';
714 echo '<h3>'.__('Preserving Authors').'</h3>';
715 echo '<p>'.__('Secondly, we have attempted to preserve post authors. If you are the only author or contributor to your blog, then you are safe. In most cases, we are successful in this preservation endeavor. However, if we cannot ascertain the name of the writer due to discrepancies between database tables, we assign it to you, the administrative user.').'</p>';
716 echo '<h3>'.__('Textile').'</h3>';
717 echo '<p>'.__('Also, since you\'re coming from DotClear, you probably have been using Textile to format your comments and posts. If this is the case, we recommend downloading and installing <a href="http://www.huddledmasses.org/category/development/wordpress/textile/">Textile for WordPress</a>. Trust me... You\'ll want it.').'</p>';
718 echo '<h3>'.__('WordPress Resources').'</h3>';
719 echo '<p>'.__('Finally, there are numerous WordPress resources around the internet. Some of them are:').'</p>';
721 echo '<li>'.__('<a href="http://www.wordpress.org">The official WordPress site</a>').'</li>';
722 echo '<li>'.__('<a href="http://wordpress.org/support/">The WordPress support forums</a>').'</li>';
723 echo '<li>'.__('<a href="http://codex.wordpress.org">The Codex (In other words, the WordPress Bible)</a>').'</li>';
725 echo '<p>'.sprintf(__('That\'s it! What are you waiting for? Go <a href="%1$s">login</a>!'), '../wp-login.php').'</p>';
730 echo '<table class="form-table">';
731 printf('<tr><th><label for="dbuser">%s</label></th><td><input type="text" name="dbuser" id="dbuser" /></td></tr>', __('DotClear Database User:'));
732 printf('<tr><th><label for="dbpass">%s</label></th><td><input type="password" name="dbpass" id="dbpass" /></td></tr>', __('DotClear Database Password:'));
733 printf('<tr><th><label for="dbname">%s</label></th><td><input type="text" name="dbname" id="dbname" /></td></tr>', __('DotClear Database Name:'));
734 printf('<tr><th><label for="dbhost">%s</label></th><td><input type="text" name="dbhost" id="dbhost" value="localhost" /></td></tr>', __('DotClear Database Host:'));
735 printf('<tr><th><label for="dbprefix">%s</label></th><td><input type="text" name="dbprefix" id="dbprefix" value="dc_"/></td></tr>', __('DotClear Table prefix:'));
736 printf('<tr><th><label for="dccharset">%s</label></th><td><input type="text" name="dccharset" id="dccharset" value="ISO-8859-15"/></td></tr>', __('Originating character set:'));
743 if (empty ($_GET['step']))
746 $step = (int) $_GET['step'];
751 check_admin_referer('import-dotclear');
755 if(get_option('dcuser'))
756 delete_option('dcuser');
757 add_option('dcuser', sanitize_user($_POST['dbuser'], true));
761 if(get_option('dcpass'))
762 delete_option('dcpass');
763 add_option('dcpass', sanitize_user($_POST['dbpass'], true));
768 if(get_option('dcname'))
769 delete_option('dcname');
770 add_option('dcname', sanitize_user($_POST['dbname'], true));
774 if(get_option('dchost'))
775 delete_option('dchost');
776 add_option('dchost', sanitize_user($_POST['dbhost'], true));
778 if($_POST['dccharset'])
780 if(get_option('dccharset'))
781 delete_option('dccharset');
782 add_option('dccharset', sanitize_user($_POST['dccharset'], true));
784 if($_POST['dbprefix'])
786 if(get_option('dcdbprefix'))
787 delete_option('dcdbprefix');
788 add_option('dcdbprefix', sanitize_user($_POST['dbprefix'], true));
801 $this->import_categories();
804 $this->import_users();
807 $result = $this->import_posts();
808 if ( is_wp_error( $result ) )
809 echo $result->get_error_message();
812 $this->import_comments();
815 $this->import_links();
818 $this->cleanup_dcimport();
825 function Dotclear_Import()
831 $dc_import = new Dotclear_Import();
833 register_importer('dotclear', __('DotClear'), __('Import categories, users, posts, comments, and links from a DotClear blog.'), array ($dc_import, 'dispatch'));