3 * DotClear import plugin
4 * by Thomas Quinot - http://thomas.quinot.org/
8 Add These Functions to make our lives easier
11 if(!function_exists('get_comment_count'))
13 function get_comment_count($post_ID)
16 return $wpdb->get_var('SELECT count(*) FROM '.$wpdb->comments.' WHERE comment_post_ID = '.$post_ID);
20 if(!function_exists('link_exists'))
22 function link_exists($linkname)
25 return $wpdb->get_var('SELECT link_id FROM '.$wpdb->links.' WHERE link_name = "'.$linkname.'"');
31 Taken from http://www.php.net/manual/fr/function.mb-detect-encoding.php#50087
34 // utf8 encoding validation developed based on Wikipedia entry at:
35 // http://en.wikipedia.org/wiki/UTF-8
37 // Implemented as a recursive descent parser based on a simple state machine
38 // copyright 2005 Maarten Meijer
40 // This cries out for a C-implementation to be included in PHP core
43 function valid_1byte($char) {
44 if(!is_int($char)) return false;
45 return ($char & 0x80) == 0x00;
48 function valid_2byte($char) {
49 if(!is_int($char)) return false;
50 return ($char & 0xE0) == 0xC0;
53 function valid_3byte($char) {
54 if(!is_int($char)) return false;
55 return ($char & 0xF0) == 0xE0;
58 function valid_4byte($char) {
59 if(!is_int($char)) return false;
60 return ($char & 0xF8) == 0xF0;
63 function valid_nextbyte($char) {
64 if(!is_int($char)) return false;
65 return ($char & 0xC0) == 0x80;
68 function valid_utf8($string) {
69 $len = strlen($string);
72 $char = ord(substr($string, $i++, 1));
73 if(valid_1byte($char)) { // continue
75 } else if(valid_2byte($char)) { // check 1 byte
76 if(!valid_nextbyte(ord(substr($string, $i++, 1))))
78 } else if(valid_3byte($char)) { // check 2 bytes
79 if(!valid_nextbyte(ord(substr($string, $i++, 1))))
81 if(!valid_nextbyte(ord(substr($string, $i++, 1))))
83 } else if(valid_4byte($char)) { // check 3 bytes
84 if(!valid_nextbyte(ord(substr($string, $i++, 1))))
86 if(!valid_nextbyte(ord(substr($string, $i++, 1))))
88 if(!valid_nextbyte(ord(substr($string, $i++, 1))))
96 if (valid_utf8 ($s)) {
99 return iconv(get_option ("dccharset"),"UTF-8",$s);
103 function textconv ($s) {
104 return csc (preg_replace ('|(?<!<br />)\s*\n|', ' ', $s));
108 The Main Importer Class
110 class Dotclear_Import {
114 echo '<div class="wrap">';
115 echo '<h2>'.__('Import DotClear').'</h2>';
116 echo '<p>'.__('Steps may take a few minutes depending on the size of your database. Please be patient.').'</p>';
126 echo '<div class="narrow"><p>'.__('Howdy! This importer allows you to extract posts from a DotClear database into your blog. Mileage may vary.').'</p>';
127 echo '<p>'.__('Your DotClear Configuration settings are as follows:').'</p>';
128 echo '<form action="admin.php?import=dotclear&step=1" method="post">';
129 wp_nonce_field('import-dotclear');
131 echo '<p class="submit"><input type="submit" name="submit" value="'.attribute_escape(__('Import Categories »')).'" /></p>';
132 echo '</form></div>';
135 function get_dc_cats()
138 // General Housekeeping
139 $dcdb = new wpdb(get_option('dcuser'), get_option('dcpass'), get_option('dcname'), get_option('dchost'));
140 set_magic_quotes_runtime(0);
141 $dbprefix = get_option('dcdbprefix');
144 return $dcdb->get_results('SELECT * FROM '.$dbprefix.'categorie', ARRAY_A);
147 function get_dc_users()
150 // General Housekeeping
151 $dcdb = new wpdb(get_option('dcuser'), get_option('dcpass'), get_option('dcname'), get_option('dchost'));
152 set_magic_quotes_runtime(0);
153 $dbprefix = get_option('dcdbprefix');
157 return $dcdb->get_results('SELECT * FROM '.$dbprefix.'user', ARRAY_A);
160 function get_dc_posts()
162 // General Housekeeping
163 $dcdb = new wpdb(get_option('dcuser'), get_option('dcpass'), get_option('dcname'), get_option('dchost'));
164 set_magic_quotes_runtime(0);
165 $dbprefix = get_option('dcdbprefix');
168 return $dcdb->get_results('SELECT '.$dbprefix.'post.*, '.$dbprefix.'categorie.cat_libelle_url AS post_cat_name
169 FROM '.$dbprefix.'post INNER JOIN '.$dbprefix.'categorie
170 ON '.$dbprefix.'post.cat_id = '.$dbprefix.'categorie.cat_id', ARRAY_A);
173 function get_dc_comments()
176 // General Housekeeping
177 $dcdb = new wpdb(get_option('dcuser'), get_option('dcpass'), get_option('dcname'), get_option('dchost'));
178 set_magic_quotes_runtime(0);
179 $dbprefix = get_option('dcdbprefix');
182 return $dcdb->get_results('SELECT * FROM '.$dbprefix.'comment', ARRAY_A);
185 function get_dc_links()
187 //General Housekeeping
188 $dcdb = new wpdb(get_option('dcuser'), get_option('dcpass'), get_option('dcname'), get_option('dchost'));
189 set_magic_quotes_runtime(0);
190 $dbprefix = get_option('dcdbprefix');
192 return $dcdb->get_results('SELECT * FROM '.$dbprefix.'link ORDER BY position', ARRAY_A);
195 function cat2wp($categories='')
197 // General Housekeeping
200 $dccat2wpcat = array();
202 if(is_array($categories))
204 echo '<p>'.__('Importing Categories...').'<br /><br /></p>';
205 foreach ($categories as $category)
210 // Make Nice Variables
211 $name = $wpdb->escape($cat_libelle_url);
212 $title = $wpdb->escape(csc ($cat_libelle));
213 $desc = $wpdb->escape(csc ($cat_desc));
215 if($cinfo = category_exists($name))
217 $ret_id = wp_insert_category(array('cat_ID' => $cinfo, 'category_nicename' => $name, 'cat_name' => $title, 'category_description' => $desc));
221 $ret_id = wp_insert_category(array('category_nicename' => $name, 'cat_name' => $title, 'category_description' => $desc));
223 $dccat2wpcat[$id] = $ret_id;
226 // Store category translation for future use
227 add_option('dccat2wpcat',$dccat2wpcat);
228 echo '<p>'.sprintf(__('Done! <strong>%1$s</strong> categories imported.'), $count).'<br /><br /></p>';
231 echo __('No Categories to Import!');
235 function users2wp($users='')
237 // General Housekeeping
240 $dcid2wpid = array();
245 echo '<p>'.__('Importing Users...').'<br /><br /></p>';
246 foreach($users as $user)
251 // Make Nice Variables
252 $name = $wpdb->escape(csc ($name));
253 $RealName = $wpdb->escape(csc ($user_pseudo));
255 if($uinfo = get_userdatabylogin($name))
258 $ret_id = wp_insert_user(array(
260 'user_login' => $user_id,
261 'user_nicename' => $Realname,
262 'user_email' => $user_email,
263 'user_url' => 'http://',
264 'display_name' => $Realname)
269 $ret_id = wp_insert_user(array(
270 'user_login' => $user_id,
271 'user_nicename' => csc ($user_pseudo),
272 'user_email' => $user_email,
273 'user_url' => 'http://',
274 'display_name' => $Realname)
277 $dcid2wpid[$user_id] = $ret_id;
279 // Set DotClear-to-WordPress permissions translation
281 // Update Usermeta Data
282 $user = new WP_User($ret_id);
283 $wp_perms = $user_level + 1;
284 if(10 == $wp_perms) { $user->set_role('administrator'); }
285 else if(9 == $wp_perms) { $user->set_role('editor'); }
286 else if(5 <= $wp_perms) { $user->set_role('editor'); }
287 else if(4 <= $wp_perms) { $user->set_role('author'); }
288 else if(3 <= $wp_perms) { $user->set_role('contributor'); }
289 else if(2 <= $wp_perms) { $user->set_role('contributor'); }
290 else { $user->set_role('subscriber'); }
292 update_usermeta( $ret_id, 'wp_user_level', $wp_perms);
293 update_usermeta( $ret_id, 'rich_editing', 'false');
294 update_usermeta( $ret_id, 'first_name', csc ($user_prenom));
295 update_usermeta( $ret_id, 'last_name', csc ($user_nom));
296 }// End foreach($users as $user)
298 // Store id translation array for future use
299 add_option('dcid2wpid',$dcid2wpid);
302 echo '<p>'.sprintf(__('Done! <strong>%1$s</strong> users imported.'), $count).'<br /><br /></p>';
304 }// End if(is_array($users)
306 echo __('No Users to Import!');
309 }// End function user2wp()
311 function posts2wp($posts='')
313 // General Housekeeping
316 $dcposts2wpposts = array();
322 echo '<p>'.__('Importing Posts...').'<br /><br /></p>';
323 foreach($posts as $post)
328 // Set DotClear-to-WordPress status translation
329 $stattrans = array(0 => 'draft', 1 => 'publish');
330 $comment_status_map = array (0 => 'closed', 1 => 'open');
332 //Can we do this more efficiently?
333 $uinfo = ( get_userdatabylogin( $user_id ) ) ? get_userdatabylogin( $user_id ) : 1;
334 $authorid = ( is_object( $uinfo ) ) ? $uinfo->ID : $uinfo ;
336 $Title = $wpdb->escape(csc ($post_titre));
337 $post_content = textconv ($post_content);
339 if ($post_chapo != "") {
340 $post_excerpt = textconv ($post_chapo);
341 $post_content = $post_excerpt ."\n<!--more-->\n".$post_content;
343 $post_excerpt = $wpdb->escape ($post_excerpt);
344 $post_content = $wpdb->escape ($post_content);
345 $post_status = $stattrans[$post_pub];
347 // Import Post data into WordPress
349 if($pinfo = post_exists($Title,$post_content))
351 $ret_id = wp_insert_post(array(
353 'post_author' => $authorid,
354 'post_date' => $post_dt,
355 'post_date_gmt' => $post_dt,
356 'post_modified' => $post_upddt,
357 'post_modified_gmt' => $post_upddt,
358 'post_title' => $Title,
359 'post_content' => $post_content,
360 'post_excerpt' => $post_excerpt,
361 'post_status' => $post_status,
362 'post_name' => $post_titre_url,
363 'comment_status' => $comment_status_map[$post_open_comment],
364 'ping_status' => $comment_status_map[$post_open_tb],
365 'comment_count' => $post_nb_comment + $post_nb_trackback)
367 if ( is_wp_error( $ret_id ) )
372 $ret_id = wp_insert_post(array(
373 'post_author' => $authorid,
374 'post_date' => $post_dt,
375 'post_date_gmt' => $post_dt,
376 'post_modified' => $post_modified_gmt,
377 'post_modified_gmt' => $post_modified_gmt,
378 'post_title' => $Title,
379 'post_content' => $post_content,
380 'post_excerpt' => $post_excerpt,
381 'post_status' => $post_status,
382 'post_name' => $post_titre_url,
383 'comment_status' => $comment_status_map[$post_open_comment],
384 'ping_status' => $comment_status_map[$post_open_tb],
385 'comment_count' => $post_nb_comment + $post_nb_trackback)
387 if ( is_wp_error( $ret_id ) )
390 $dcposts2wpposts[$post_id] = $ret_id;
392 // Make Post-to-Category associations
394 $category1 = get_category_by_slug($post_cat_name);
395 $category1 = $category1->term_id;
397 if($cat1 = $category1) { $cats[1] = $cat1; }
399 if(!empty($cats)) { wp_set_post_categories($ret_id, $cats); }
402 // Store ID translation for later use
403 add_option('dcposts2wpposts',$dcposts2wpposts);
405 echo '<p>'.sprintf(__('Done! <strong>%1$s</strong> posts imported.'), $count).'<br /><br /></p>';
409 function comments2wp($comments='')
411 // General Housekeeping
414 $dccm2wpcm = array();
415 $postarr = get_option('dcposts2wpposts');
418 if(is_array($comments))
420 echo '<p>'.__('Importing Comments...').'<br /><br /></p>';
421 foreach($comments as $comment)
427 $comment_ID = (int) ltrim($comment_id, '0');
428 $comment_post_ID = (int) $postarr[$post_id];
429 $comment_approved = "$comment_pub";
430 $name = $wpdb->escape(csc ($comment_auteur));
431 $email = $wpdb->escape($comment_email);
432 $web = "http://".$wpdb->escape($comment_site);
433 $message = $wpdb->escape(textconv ($comment_content));
435 if($cinfo = comment_exists($name, $comment_dt))
438 $ret_id = wp_update_comment(array(
439 'comment_ID' => $cinfo,
440 'comment_post_ID' => $comment_post_ID,
441 'comment_author' => $name,
442 'comment_author_email' => $email,
443 'comment_author_url' => $web,
444 'comment_author_IP' => $comment_ip,
445 'comment_date' => $comment_dt,
446 'comment_date_gmt' => $comment_dt,
447 'comment_content' => $message,
448 'comment_approved' => $comment_approved)
454 $ret_id = wp_insert_comment(array(
455 'comment_post_ID' => $comment_post_ID,
456 'comment_author' => $name,
457 'comment_author_email' => $email,
458 'comment_author_url' => $web,
459 'comment_author_IP' => $comment_ip,
460 'comment_date' => $comment_dt,
461 'comment_date_gmt' => $comment_dt,
462 'comment_content' => $message,
463 'comment_approved' => $comment_approved)
466 $dccm2wpcm[$comment_ID] = $ret_id;
468 // Store Comment ID translation for future use
469 add_option('dccm2wpcm', $dccm2wpcm);
471 // Associate newly formed categories with posts
472 get_comment_count($ret_id);
475 echo '<p>'.sprintf(__('Done! <strong>%1$s</strong> comments imported.'), $count).'<br /><br /></p>';
478 echo __('No Comments to Import!');
482 function links2wp($links='')
484 // General Housekeeping
488 // Deal with the links
491 echo '<p>'.__('Importing Links...').'<br /><br /></p>';
492 foreach($links as $link)
498 if ($cinfo = is_term(csc ($title), 'link_category')) {
499 $category = $cinfo['term_id'];
501 $category = wp_insert_term($wpdb->escape (csc ($title)), 'link_category');
502 $category = $category['term_id'];
505 $linkname = $wpdb->escape(csc ($label));
506 $description = $wpdb->escape(csc ($title));
508 if($linfo = link_exists($linkname)) {
509 $ret_id = wp_insert_link(array(
512 'link_name' => $linkname,
513 'link_category' => $category,
514 'link_description' => $description)
517 $ret_id = wp_insert_link(array(
519 'link_name' => $linkname,
520 'link_category' => $category,
521 'link_description' => $description)
524 $dclinks2wplinks[$link_id] = $ret_id;
527 add_option('dclinks2wplinks',$dclinks2wplinks);
529 printf(__('Done! <strong>%s</strong> links or link categories imported'), $count);
530 echo '<br /><br /></p>';
533 echo __('No Links to Import!');
537 function import_categories()
540 $cats = $this->get_dc_cats();
541 $this->cat2wp($cats);
542 add_option('dc_cats', $cats);
546 echo '<form action="admin.php?import=dotclear&step=2" method="post">';
547 wp_nonce_field('import-dotclear');
548 printf('<input type="submit" name="submit" value="%s" />', attribute_escape(__('Import Users')));
553 function import_users()
556 $users = $this->get_dc_users();
557 $this->users2wp($users);
559 echo '<form action="admin.php?import=dotclear&step=3" method="post">';
560 wp_nonce_field('import-dotclear');
561 printf('<input type="submit" name="submit" value="%s" />', attribute_escape(__('Import Posts')));
565 function import_posts()
568 $posts = $this->get_dc_posts();
569 $result = $this->posts2wp($posts);
570 if ( is_wp_error( $result ) )
573 echo '<form action="admin.php?import=dotclear&step=4" method="post">';
574 wp_nonce_field('import-dotclear');
575 printf('<input type="submit" name="submit" value="%s" />', attribute_escape(__('Import Comments')));
579 function import_comments()
582 $comments = $this->get_dc_comments();
583 $this->comments2wp($comments);
585 echo '<form action="admin.php?import=dotclear&step=5" method="post">';
586 wp_nonce_field('import-dotclear');
587 printf('<input type="submit" name="submit" value="%s" />', attribute_escape(__('Import Links')));
591 function import_links()
594 $links = $this->get_dc_links();
595 $this->links2wp($links);
596 add_option('dc_links', $links);
598 echo '<form action="admin.php?import=dotclear&step=6" method="post">';
599 wp_nonce_field('import-dotclear');
600 printf('<input type="submit" name="submit" value="%s" />', attribute_escape(__('Finish')));
604 function cleanup_dcimport()
606 delete_option('dcdbprefix');
607 delete_option('dc_cats');
608 delete_option('dcid2wpid');
609 delete_option('dccat2wpcat');
610 delete_option('dcposts2wpposts');
611 delete_option('dccm2wpcm');
612 delete_option('dclinks2wplinks');
613 delete_option('dcuser');
614 delete_option('dcpass');
615 delete_option('dcname');
616 delete_option('dchost');
617 delete_option('dccharset');
623 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>';
624 echo '<h3>'.__('Users').'</h3>';
625 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>';
626 echo '<h3>'.__('Preserving Authors').'</h3>';
627 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>';
628 echo '<h3>'.__('Textile').'</h3>';
629 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>';
630 echo '<h3>'.__('WordPress Resources').'</h3>';
631 echo '<p>'.__('Finally, there are numerous WordPress resources around the internet. Some of them are:').'</p>';
633 echo '<li>'.__('<a href="http://www.wordpress.org">The official WordPress site</a>').'</li>';
634 echo '<li>'.__('<a href="http://wordpress.org/support/">The WordPress support forums</a>').'</li>';
635 echo '<li>'.__('<a href="http://codex.wordpress.org">The Codex (In other words, the WordPress Bible)</a>').'</li>';
637 echo '<p>'.sprintf(__('That\'s it! What are you waiting for? Go <a href="%1$s">login</a>!'), '../wp-login.php').'</p>';
642 echo '<table class="editform">';
643 printf('<tr><th><label for="dbuser">%s</label></th><td><input type="text" name="dbuser" id="dbuser" /></td></tr>', __('DotClear Database User:'));
644 printf('<tr><th><label for="dbpass">%s</label></th><td><input type="password" name="dbpass" id="dbpass" /></td></tr>', __('DotClear Database Password:'));
645 printf('<tr><th><label for="dbname">%s</label></th><td><input type="text" name="dbname" id="dbname" /></td></tr>', __('DotClear Database Name:'));
646 printf('<tr><th><label for="dbhost">%s</label></th><td><input type="text" name="dbhost" nameid="dbhost" value="localhost" /></td></tr>', __('DotClear Database Host:'));
647 printf('<tr><th><label for="dbprefix">%s</label></th><td><input type="text" name="dbprefix" id="dbprefix" value="dc_"/></td></tr>', __('DotClear Table prefix:'));
648 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:'));
655 if (empty ($_GET['step']))
658 $step = (int) $_GET['step'];
663 check_admin_referer('import-dotclear');
667 if(get_option('dcuser'))
668 delete_option('dcuser');
669 add_option('dcuser', sanitize_user($_POST['dbuser'], true));
673 if(get_option('dcpass'))
674 delete_option('dcpass');
675 add_option('dcpass', sanitize_user($_POST['dbpass'], true));
680 if(get_option('dcname'))
681 delete_option('dcname');
682 add_option('dcname', sanitize_user($_POST['dbname'], true));
686 if(get_option('dchost'))
687 delete_option('dchost');
688 add_option('dchost', sanitize_user($_POST['dbhost'], true));
690 if($_POST['dccharset'])
692 if(get_option('dccharset'))
693 delete_option('dccharset');
694 add_option('dccharset', sanitize_user($_POST['dccharset'], true));
696 if($_POST['dbprefix'])
698 if(get_option('dcdbprefix'))
699 delete_option('dcdbprefix');
700 add_option('dcdbprefix', sanitize_user($_POST['dbprefix'], true));
713 $this->import_categories();
716 $this->import_users();
719 $result = $this->import_posts();
720 if ( is_wp_error( $result ) )
721 echo $result->get_error_message();
724 $this->import_comments();
727 $this->import_links();
730 $this->cleanup_dcimport();
737 function Dotclear_Import()
743 $dc_import = new Dotclear_Import();
744 register_importer('dotclear', __('DotClear'), __('Import categories, users, posts, comments, and links from a DotClear blog'), array ($dc_import, 'dispatch'));