3 * DotClear import plugin
4 * by Thomas Quinot - http://thomas.quinot.org/
8 Add These Functions to make our lives easier
10 if(!function_exists('get_catbynicename'))
12 function get_catbynicename($category_nicename)
16 $cat_id -= 0; // force numeric
17 $name = $wpdb->get_var('SELECT cat_ID FROM '.$wpdb->categories.' WHERE category_nicename="'.$category_nicename.'"');
23 if(!function_exists('get_comment_count'))
25 function get_comment_count($post_ID)
28 return $wpdb->get_var('SELECT count(*) FROM '.$wpdb->comments.' WHERE comment_post_ID = '.$post_ID);
32 if(!function_exists('link_cat_exists'))
34 function link_cat_exists($catname)
37 return $wpdb->get_var('SELECT cat_id FROM '.$wpdb->linkcategories.' WHERE cat_name = "'.$wpdb->escape($catname).'"');
41 if(!function_exists('link_exists'))
43 function link_exists($linkname)
46 return $wpdb->get_var('SELECT link_id FROM '.$wpdb->links.' WHERE link_name = "'.$linkname.'"');
52 Taken from http://www.php.net/manual/fr/function.mb-detect-encoding.php#50087
55 // utf8 encoding validation developed based on Wikipedia entry at:
56 // http://en.wikipedia.org/wiki/UTF-8
58 // Implemented as a recursive descent parser based on a simple state machine
59 // copyright 2005 Maarten Meijer
61 // This cries out for a C-implementation to be included in PHP core
64 function valid_1byte($char) {
65 if(!is_int($char)) return false;
66 return ($char & 0x80) == 0x00;
69 function valid_2byte($char) {
70 if(!is_int($char)) return false;
71 return ($char & 0xE0) == 0xC0;
74 function valid_3byte($char) {
75 if(!is_int($char)) return false;
76 return ($char & 0xF0) == 0xE0;
79 function valid_4byte($char) {
80 if(!is_int($char)) return false;
81 return ($char & 0xF8) == 0xF0;
84 function valid_nextbyte($char) {
85 if(!is_int($char)) return false;
86 return ($char & 0xC0) == 0x80;
89 function valid_utf8($string) {
90 $len = strlen($string);
93 $char = ord(substr($string, $i++, 1));
94 if(valid_1byte($char)) { // continue
96 } else if(valid_2byte($char)) { // check 1 byte
97 if(!valid_nextbyte(ord(substr($string, $i++, 1))))
99 } else if(valid_3byte($char)) { // check 2 bytes
100 if(!valid_nextbyte(ord(substr($string, $i++, 1))))
102 if(!valid_nextbyte(ord(substr($string, $i++, 1))))
104 } else if(valid_4byte($char)) { // check 3 bytes
105 if(!valid_nextbyte(ord(substr($string, $i++, 1))))
107 if(!valid_nextbyte(ord(substr($string, $i++, 1))))
109 if(!valid_nextbyte(ord(substr($string, $i++, 1))))
117 if (valid_utf8 ($s)) {
120 return iconv(get_option ("dccharset"),"UTF-8",$s);
124 function textconv ($s) {
125 return csc (preg_replace ('|(?<!<br />)\s*\n|', ' ', $s));
129 The Main Importer Class
131 class Dotclear_Import {
135 echo '<div class="wrap">';
136 echo '<h2>'.__('Import DotClear').'</h2>';
137 echo '<p>'.__('Steps may take a few minutes depending on the size of your database. Please be patient.').'</p>';
147 echo '<div class="narrow"><p>'.__('Howdy! This importer allows you to extract posts from a DotClear database into your blog. Mileage may vary.').'</p>';
148 echo '<p>'.__('Your DotClear Configuration settings are as follows:').'</p>';
149 echo '<form action="admin.php?import=dotclear&step=1" method="post">';
150 wp_nonce_field('import-dotclear');
152 echo '<p class="submit"><input type="submit" name="submit" value="'.attribute_escape(__('Import Categories »')).'" /></p>';
153 echo '</form></div>';
156 function get_dc_cats()
159 // General Housekeeping
160 $dcdb = new wpdb(get_option('dcuser'), get_option('dcpass'), get_option('dcname'), get_option('dchost'));
161 set_magic_quotes_runtime(0);
162 $dbprefix = get_option('dcdbprefix');
165 return $dcdb->get_results('SELECT * FROM '.$dbprefix.'categorie', ARRAY_A);
168 function get_dc_users()
171 // General Housekeeping
172 $dcdb = new wpdb(get_option('dcuser'), get_option('dcpass'), get_option('dcname'), get_option('dchost'));
173 set_magic_quotes_runtime(0);
174 $dbprefix = get_option('dcdbprefix');
178 return $dcdb->get_results('SELECT * FROM '.$dbprefix.'user', ARRAY_A);
181 function get_dc_posts()
183 // General Housekeeping
184 $dcdb = new wpdb(get_option('dcuser'), get_option('dcpass'), get_option('dcname'), get_option('dchost'));
185 set_magic_quotes_runtime(0);
186 $dbprefix = get_option('dcdbprefix');
189 return $dcdb->get_results('SELECT '.$dbprefix.'post.*, '.$dbprefix.'categorie.cat_libelle_url AS post_cat_name
190 FROM '.$dbprefix.'post INNER JOIN '.$dbprefix.'categorie
191 ON '.$dbprefix.'post.cat_id = '.$dbprefix.'categorie.cat_id', ARRAY_A);
194 function get_dc_comments()
197 // General Housekeeping
198 $dcdb = new wpdb(get_option('dcuser'), get_option('dcpass'), get_option('dcname'), get_option('dchost'));
199 set_magic_quotes_runtime(0);
200 $dbprefix = get_option('dcdbprefix');
203 return $dcdb->get_results('SELECT * FROM '.$dbprefix.'comment', ARRAY_A);
206 function get_dc_links()
208 //General Housekeeping
209 $dcdb = new wpdb(get_option('dcuser'), get_option('dcpass'), get_option('dcname'), get_option('dchost'));
210 set_magic_quotes_runtime(0);
211 $dbprefix = get_option('dcdbprefix');
213 return $dcdb->get_results('SELECT * FROM '.$dbprefix.'link ORDER BY position', ARRAY_A);
216 function cat2wp($categories='')
218 // General Housekeeping
221 $dccat2wpcat = array();
223 if(is_array($categories))
225 echo '<p>'.__('Importing Categories...').'<br /><br /></p>';
226 foreach ($categories as $category)
231 // Make Nice Variables
232 $name = $wpdb->escape($cat_libelle_url);
233 $title = $wpdb->escape(csc ($cat_libelle));
234 $desc = $wpdb->escape(csc ($cat_desc));
236 if($cinfo = category_exists($name))
238 $ret_id = wp_insert_category(array('cat_ID' => $cinfo, 'category_nicename' => $name, 'cat_name' => $title, 'category_description' => $desc));
242 $ret_id = wp_insert_category(array('category_nicename' => $name, 'cat_name' => $title, 'category_description' => $desc));
244 $dccat2wpcat[$id] = $ret_id;
247 // Store category translation for future use
248 add_option('dccat2wpcat',$dccat2wpcat);
249 echo '<p>'.sprintf(__('Done! <strong>%1$s</strong> categories imported.'), $count).'<br /><br /></p>';
252 echo __('No Categories to Import!');
256 function users2wp($users='')
258 // General Housekeeping
261 $dcid2wpid = array();
266 echo '<p>'.__('Importing Users...').'<br /><br /></p>';
267 foreach($users as $user)
272 // Make Nice Variables
273 $name = $wpdb->escape(csc ($name));
274 $RealName = $wpdb->escape(csc ($user_pseudo));
276 if($uinfo = get_userdatabylogin($name))
279 $ret_id = wp_insert_user(array(
281 'user_login' => $user_id,
282 'user_nicename' => $Realname,
283 'user_email' => $user_email,
284 'user_url' => 'http://',
285 'display_name' => $Realname)
290 $ret_id = wp_insert_user(array(
291 'user_login' => $user_id,
292 'user_nicename' => csc ($user_pseudo),
293 'user_email' => $user_email,
294 'user_url' => 'http://',
295 'display_name' => $Realname)
298 $dcid2wpid[$user_id] = $ret_id;
300 // Set DotClear-to-WordPress permissions translation
302 // Update Usermeta Data
303 $user = new WP_User($ret_id);
304 $wp_perms = $user_level + 1;
305 if(10 == $wp_perms) { $user->set_role('administrator'); }
306 else if(9 == $wp_perms) { $user->set_role('editor'); }
307 else if(5 <= $wp_perms) { $user->set_role('editor'); }
308 else if(4 <= $wp_perms) { $user->set_role('author'); }
309 else if(3 <= $wp_perms) { $user->set_role('contributor'); }
310 else if(2 <= $wp_perms) { $user->set_role('contributor'); }
311 else { $user->set_role('subscriber'); }
313 update_usermeta( $ret_id, 'wp_user_level', $wp_perms);
314 update_usermeta( $ret_id, 'rich_editing', 'false');
315 update_usermeta( $ret_id, 'first_name', csc ($user_prenom));
316 update_usermeta( $ret_id, 'last_name', csc ($user_nom));
317 }// End foreach($users as $user)
319 // Store id translation array for future use
320 add_option('dcid2wpid',$dcid2wpid);
323 echo '<p>'.sprintf(__('Done! <strong>%1$s</strong> users imported.'), $count).'<br /><br /></p>';
325 }// End if(is_array($users)
327 echo __('No Users to Import!');
330 }// End function user2wp()
332 function posts2wp($posts='')
334 // General Housekeeping
337 $dcposts2wpposts = array();
343 echo '<p>'.__('Importing Posts...').'<br /><br /></p>';
344 foreach($posts as $post)
349 // Set DotClear-to-WordPress status translation
350 $stattrans = array(0 => 'draft', 1 => 'publish');
351 $comment_status_map = array (0 => 'closed', 1 => 'open');
353 //Can we do this more efficiently?
354 $uinfo = ( get_userdatabylogin( $user_id ) ) ? get_userdatabylogin( $user_id ) : 1;
355 $authorid = ( is_object( $uinfo ) ) ? $uinfo->ID : $uinfo ;
357 $Title = $wpdb->escape(csc ($post_titre));
358 $post_content = textconv ($post_content);
360 if ($post_chapo != "") {
361 $post_excerpt = textconv ($post_chapo);
362 $post_content = $post_excerpt ."\n<!--more-->\n".$post_content;
364 $post_excerpt = $wpdb->escape ($post_excerpt);
365 $post_content = $wpdb->escape ($post_content);
366 $post_status = $stattrans[$post_pub];
368 // Import Post data into WordPress
370 if($pinfo = post_exists($Title,$post_content))
372 $ret_id = wp_insert_post(array(
374 'post_author' => $authorid,
375 'post_date' => $post_dt,
376 'post_date_gmt' => $post_dt,
377 'post_modified' => $post_upddt,
378 'post_modified_gmt' => $post_upddt,
379 'post_title' => $Title,
380 'post_content' => $post_content,
381 'post_excerpt' => $post_excerpt,
382 'post_status' => $post_status,
383 'post_name' => $post_titre_url,
384 'comment_status' => $comment_status_map[$post_open_comment],
385 'ping_status' => $comment_status_map[$post_open_tb],
386 'comment_count' => $post_nb_comment + $post_nb_trackback)
391 $ret_id = wp_insert_post(array(
392 'post_author' => $authorid,
393 'post_date' => $post_dt,
394 'post_date_gmt' => $post_dt,
395 'post_modified' => $post_modified_gmt,
396 'post_modified_gmt' => $post_modified_gmt,
397 'post_title' => $Title,
398 'post_content' => $post_content,
399 'post_excerpt' => $post_excerpt,
400 'post_status' => $post_status,
401 'post_name' => $post_titre_url,
402 'comment_status' => $comment_status_map[$post_open_comment],
403 'ping_status' => $comment_status_map[$post_open_tb],
404 'comment_count' => $post_nb_comment + $post_nb_trackback)
407 $dcposts2wpposts[$post_id] = $ret_id;
409 // Make Post-to-Category associations
411 if($cat1 = get_catbynicename($post_cat_name)) { $cats[1] = $cat1; }
413 if(!empty($cats)) { wp_set_post_cats('', $ret_id, $cats); }
416 // Store ID translation for later use
417 add_option('dcposts2wpposts',$dcposts2wpposts);
419 echo '<p>'.sprintf(__('Done! <strong>%1$s</strong> posts imported.'), $count).'<br /><br /></p>';
423 function comments2wp($comments='')
425 // General Housekeeping
428 $dccm2wpcm = array();
429 $postarr = get_option('dcposts2wpposts');
432 if(is_array($comments))
434 echo '<p>'.__('Importing Comments...').'<br /><br /></p>';
435 foreach($comments as $comment)
441 $comment_ID = (int) ltrim($comment_id, '0');
442 $comment_post_ID = (int) $postarr[$post_id];
443 $comment_approved = "$comment_pub";
444 $name = $wpdb->escape(csc ($comment_auteur));
445 $email = $wpdb->escape($comment_email);
446 $web = "http://".$wpdb->escape($comment_site);
447 $message = $wpdb->escape(textconv ($comment_content));
449 if($cinfo = comment_exists($name, $comment_dt))
452 $ret_id = wp_update_comment(array(
453 'comment_ID' => $cinfo,
454 'comment_post_ID' => $comment_post_ID,
455 'comment_author' => $name,
456 'comment_author_email' => $email,
457 'comment_author_url' => $web,
458 'comment_author_IP' => $comment_ip,
459 'comment_date' => $comment_dt,
460 'comment_date_gmt' => $comment_dt,
461 'comment_content' => $message,
462 'comment_approved' => $comment_approved)
468 $ret_id = wp_insert_comment(array(
469 'comment_post_ID' => $comment_post_ID,
470 'comment_author' => $name,
471 'comment_author_email' => $email,
472 'comment_author_url' => $web,
473 'comment_author_IP' => $comment_ip,
474 'comment_date' => $comment_dt,
475 'comment_date_gmt' => $comment_dt,
476 'comment_content' => $message,
477 'comment_approved' => $comment_approved)
480 $dccm2wpcm[$comment_ID] = $ret_id;
482 // Store Comment ID translation for future use
483 add_option('dccm2wpcm', $dccm2wpcm);
485 // Associate newly formed categories with posts
486 get_comment_count($ret_id);
489 echo '<p>'.sprintf(__('Done! <strong>%1$s</strong> comments imported.'), $count).'<br /><br /></p>';
492 echo __('No Comments to Import!');
496 function links2wp($links='')
498 // General Housekeeping
502 // Deal with the links
505 echo '<p>'.__('Importing Links...').'<br /><br /></p>';
506 foreach($links as $link)
512 if ($cinfo = link_cat_exists (csc ($title))) {
515 $wpdb->query ("INSERT INTO $wpdb->linkcategories (cat_name) VALUES ('".
516 $wpdb->escape (csc ($title))."')");
517 $category = $wpdb->insert_id;
520 $linkname = $wpdb->escape(csc ($label));
521 $description = $wpdb->escape(csc ($title));
523 if($linfo = link_exists($linkname)) {
524 $ret_id = wp_insert_link(array(
527 'link_name' => $linkname,
528 'link_category' => $category,
529 'link_description' => $description)
532 $ret_id = wp_insert_link(array(
534 'link_name' => $linkname,
535 'link_category' => $category,
536 'link_description' => $description)
539 $dclinks2wplinks[$link_id] = $ret_id;
542 add_option('dclinks2wplinks',$dclinks2wplinks);
544 printf(__('Done! <strong>%s</strong> links or link categories imported'), $count);
545 echo '<br /><br /></p>';
548 echo __('No Links to Import!');
552 function import_categories()
555 $cats = $this->get_dc_cats();
556 $this->cat2wp($cats);
557 add_option('dc_cats', $cats);
561 echo '<form action="admin.php?import=dotclear&step=2" method="post">';
562 wp_nonce_field('import-dotclear');
563 printf('<input type="submit" name="submit" value="%s" />', attribute_escape(__('Import Users')));
568 function import_users()
571 $users = $this->get_dc_users();
572 $this->users2wp($users);
574 echo '<form action="admin.php?import=dotclear&step=3" method="post">';
575 wp_nonce_field('import-dotclear');
576 printf('<input type="submit" name="submit" value="%s" />', attribute_escape(__('Import Posts')));
580 function import_posts()
583 $posts = $this->get_dc_posts();
584 $this->posts2wp($posts);
586 echo '<form action="admin.php?import=dotclear&step=4" method="post">';
587 wp_nonce_field('import-dotclear');
588 printf('<input type="submit" name="submit" value="%s" />', attribute_escape(__('Import Comments')));
592 function import_comments()
595 $comments = $this->get_dc_comments();
596 $this->comments2wp($comments);
598 echo '<form action="admin.php?import=dotclear&step=5" method="post">';
599 wp_nonce_field('import-dotclear');
600 printf('<input type="submit" name="submit" value="%s" />', attribute_escape(__('Import Links')));
604 function import_links()
607 $links = $this->get_dc_links();
608 $this->links2wp($links);
609 add_option('dc_links', $links);
611 echo '<form action="admin.php?import=dotclear&step=6" method="post">';
612 wp_nonce_field('import-dotclear');
613 printf('<input type="submit" name="submit" value="%s" />', attribute_escape(__('Finish')));
617 function cleanup_dcimport()
619 delete_option('dcdbprefix');
620 delete_option('dc_cats');
621 delete_option('dcid2wpid');
622 delete_option('dccat2wpcat');
623 delete_option('dcposts2wpposts');
624 delete_option('dccm2wpcm');
625 delete_option('dclinks2wplinks');
626 delete_option('dcuser');
627 delete_option('dcpass');
628 delete_option('dcname');
629 delete_option('dchost');
630 delete_option('dccharset');
636 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>';
637 echo '<h3>'.__('Users').'</h3>';
638 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>';
639 echo '<h3>'.__('Preserving Authors').'</h3>';
640 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>';
641 echo '<h3>'.__('Textile').'</h3>';
642 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>';
643 echo '<h3>'.__('WordPress Resources').'</h3>';
644 echo '<p>'.__('Finally, there are numerous WordPress resources around the internet. Some of them are:').'</p>';
646 echo '<li>'.__('<a href="http://www.wordpress.org">The official WordPress site</a>').'</li>';
647 echo '<li>'.__('<a href="http://wordpress.org/support/">The WordPress support forums</a>').'</li>';
648 echo '<li>'.__('<a href="http://codex.wordpress.org">The Codex (In other words, the WordPress Bible)</a>').'</li>';
650 echo '<p>'.sprintf(__('That\'s it! What are you waiting for? Go <a href="%1$s">login</a>!'), '../wp-login.php').'</p>';
655 echo '<table class="editform">';
656 printf('<tr><th><label for="dbuser">%s</label></th><td><input type="text" name="dbuser" id="dbuser" /></td></tr>', __('DotClear Database User:'));
657 printf('<tr><th><label for="dbpass">%s</label></th><td><input type="password" name="dbpass" id="dbpass" /></td></tr>', __('DotClear Database Password:'));
658 printf('<tr><th><label for="dbname">%s</label></th><td><input type="text" name="dbname" id="dbname" /></td></tr>', __('DotClear Database Name:'));
659 printf('<tr><th><label for="dbhost">%s</label></th><td><input type="text" name="dbhost" nameid="dbhost" value="localhost" /></td></tr>', __('DotClear Database Host:'));
660 printf('<tr><th><label for="dbprefix">%s</label></th><td><input type="text" name="dbprefix" id="dbprefix" value="dc_"/></td></tr>', __('DotClear Table prefix:'));
661 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:'));
668 if (empty ($_GET['step']))
671 $step = (int) $_GET['step'];
676 check_admin_referer('import-dotclear');
680 if(get_option('dcuser'))
681 delete_option('dcuser');
682 add_option('dcuser', sanitize_user($_POST['dbuser'], true));
686 if(get_option('dcpass'))
687 delete_option('dcpass');
688 add_option('dcpass', sanitize_user($_POST['dbpass'], true));
693 if(get_option('dcname'))
694 delete_option('dcname');
695 add_option('dcname', sanitize_user($_POST['dbname'], true));
699 if(get_option('dchost'))
700 delete_option('dchost');
701 add_option('dchost', sanitize_user($_POST['dbhost'], true));
703 if($_POST['dccharset'])
705 if(get_option('dccharset'))
706 delete_option('dccharset');
707 add_option('dccharset', sanitize_user($_POST['dccharset'], true));
709 if($_POST['dbprefix'])
711 if(get_option('dcdbprefix'))
712 delete_option('dcdbprefix');
713 add_option('dcdbprefix', sanitize_user($_POST['dbprefix'], true));
726 $this->import_categories();
729 $this->import_users();
732 $this->import_posts();
735 $this->import_comments();
738 $this->import_links();
741 $this->cleanup_dcimport();
748 function Dotclear_Import()
754 $dc_import = new Dotclear_Import();
755 register_importer('dotclear', __('DotClear'), __('Import categories, users, posts, comments, and links from a DotClear blog'), array ($dc_import, 'dispatch'));