Worpdess to Joomla converter - Content and Comments

4 Dec, 2008  |  Written by User ImageDan (Who am I?)  |  under Blog, Code Snippets, Conversions, Tutorials

I wont go into too much detail here as to how we went about it, I simply do not have time today, and I know that people are awaiting this script.

I decided at the last minute to add comments to the import process, for the comment systems I chose both the Jom Comment module (Commercial and is integrated with the My Blog component http://azrul.com), and the Joomla! Comments module.

If you have other comment modules that you would like added to this list, please let me know and I will do my best to also write conversion for them. Personally if you can afford it I advise going with Jom Comments, it has a lot more to offer in general and is a lot cleaner all around.

With the content and comments import, there have also been some changes added to the config file. I have added settings for the batch import, the comment system you wish to import into and if you want comments added at all. The config file is first, then the content file.
I have not completed the database table clean-up at this stage, but I will be writing a GUI and clean system before actually releasing this as a full package, and at that stage will add the database clean-up.

If you want to use the system as is you need to follow these steps.

  1. Grab the config.php from the first post of the series
  2. Edit the settings, to your desired outcome
  3. download each of the other files, users.php, categories.php, content.php
  4. Upload them to your webserver (I put them in a folder called wp2Joomla, the location is not important)
  5. Go to <yourwebaddress>/wp2joomla/users.php
  6. Once completed go to <yourwebaddress>/wp2joomla/categories.php
  7. Once completed go to <yourwebaddress>/wp2joomla/content.php and click the button until it no longer appears

Thats all there is to it. I will be wrapping a better GUI around this, so you can click through each step. Remember this is pretty much beta and won’t be perfect. But it should get your content at least in place. You may need to adjust spacing. Another thing you should do is also fix your .htaccess file to run 301 redirects from your old content to your new. If you chose the option to remove the Auto Increment this should be as simple as redirecting to the new URL as the old ID’s are maintained.

 
<?php
//
// Please fill in the information below information for your two databases
//
 
// Include the ezSQL class files
require('db/ez_sql_core.php');
require('db/ez_sql_mysql.php');
 
//
// wordpress Database information
//
$wp_db_user = '';
$wp_db_host = '';
$wp_db = '';
$wp_db_pass = '';
$wp_prefix = "wp_";
 
//
// Joomla Database information
//
$j_db_user = '';
$j_db_host = '';
$j_db = '';
$j_db_pass = '';
$j_prefix = "jos_";
 
//
// Which version of Joomla, 1.5 or 1.0.x
$j_version = "1.0.13";
 
//
//How many content items to import at a time
//
$import_batch = "20";
 
//
// Set this to 1 if you want to turn off Auto Increment on the content table for the import.
// You should set this if this is a fresh Joomla install. It will mean that your Joomla
// content ID's match your WP post ID's. This means that you can easily use a .htaccess 301 redirect
// of your content items, improving SEO.
// 1 = yes, 0= no
//
$content_reset = "1";
 
//
// Import Comments
// 1 = yes, 0=no
//
$import_comments = "1";
 
//
// Choose the comment system that you would like to use
//
# Jom Comments = 1 (commercial)
# !JoomlaComment = 2 (GPL 2.0)
#
# THE COMMENT MODULE MUST BE INSTALLED
# We can add more upon request but support the above 2 as they are available for both 1.5 and 1.0, JOM Comments is a commercial product
$jom_comment_mod = "2";
 
 
?>
 
<?php
error_reporting(E_ALL);
//
// Include The configuration file
//
include('config.php');
 
//
// Create a new connection to the Wordpress Database
//
$db = new  ezSQL_mysql($wp_db_user, $wp_db_pass, $wp_db, $wp_db_host);
 
//
// Create a connection to the Joomla Database
//
$jb = new  ezSQL_mysql($j_db_user, $j_db_pass, $j_db, $j_db_host);
 
//
// This function fetches the section and category id's for Joomla! based on the old ID of Wordpress, it uses the map table we created and returns a named array
// It also grabs the new user ID as well, this User ID could be a seperate function but I figure why bother
//
function get_jos_ids($catid, $userid) {
	global $jb;
 
	if($catid==0) {
		$mapped = $jb->get_row("SELECT jos_cat_id, jos_sec_id from jos_wp_category_map where wp_cat_id=1");
	}
	else {
		$mapped = $jb->get_row("SELECT jos_cat_id, jos_sec_id from jos_wp_category_map where wp_cat_id=".$catid);
	}
 
	$jos_ids = array();
 
	$jos_ids["section"] = $mapped->jos_sec_id;
	$jos_ids["category"] = $mapped->jos_cat_id;
 
 
	$user = $jb->get_row("SELECT jos_id from jos_user_map where wp_id=".$userid);
	$jos_ids["userid"] = $user->jos_id;
 
 
	return $jos_ids;
}
 
//
// A recursive function to import our comments, and sub comments
//
function get_nested_comments($ID, $newID, $contentID)
{
	global $db, $jb, $wp_prefix, $j_prefix;
	$children = $db->get_results("select * from ".$wp_prefix."comments where comment_parent=".$ID." and comment_approved<>'spam' order by comment_ID");
 
	foreach($children as $child) {
			$j_user_id = get_jos_ids(0, $comment->user_id);
 
			if($j_user_id["userid"]=="") {
				$j_user_id["userid"]="0";
			}
			//check which comment component we are inserting into
			//we use a switch statement so that we can add to it later if we need to add other comment modules
			switch($jom_comment_mod) {
				case "1": 
					$jb->query("insert into ".$j_prefix."jomcomment (parentid, contentid, ip, comment, date, published, email, website, user_id) values(".$newID.", ".$contentID.", '".$child->comment_author_IP."', '".$child->comment_content."', '".$child->comment_date."', 1, '".$child->comment_author_email."', '".$child->comment_author_url."', ".$j_user_id["userid"].")");
				break;
				case "2":
					if($newID=="0") {
						$newID="-1";
					}
					$jb->query("insert into ".$j_prefix."comment (contentid, ip, userid, date, email, website, comment, published, parentid, usertype) values(".$contentID.", '".$child->comment_author_IP."', ".$j_user_id["userid"].", '".$child->comment_date."', '".$child->comment_author_email."', '".$child->comment_author_url."', '".$child->comment_content."', 1, ".$newID.", '')");
				break;
			}
		get_nested_comments($child->comment_ID, $jb->insert_id, $contentID);
	}
 
}
 
//
// It is highly likely that at some stage we will run into someone who has a large amount of data, and as such running this without setting it as batches will cause significant
// load issues on their server as well as the script tending to time out. As such we will need to set this to stagger the transfer in sets of 50 content items at a time. 
// there is a new settings for this in the config file, so that users can set their own limits. If it is set too high, and the page times out they will need to manually
// Delete the content that did get imported. For safety sake, we will create a table and continuously update the single ID in there so we can reference it
//
 
// Create Table to hold import records
$jb->query("CREATE TABLE IF NOT EXISTS `jos_wp_content_import` (`last_record` INT NOT NULL, `total_records` INT NOT NULL) ENGINE = MYISAM");
 
//Get the total amount of content items from wp
$content_items = $jb->get_var("SELECT count(*) FROM ".$wp_prefix."posts where post_status='publish' or post_status='draft'");
 
// Get the last record we updated from the database, if it is null we are going to insert a row with the total and the last record of 0
// Otherwise we dive into the loop. we do it this way so we won't rely on people knowing it themselves and possibly throwing off the import.
// The script is now self contained. We may also place an auto refresh in place also.
$last_updated = $jb->get_var("SELECT last_record from jos_wp_content_import");
 
if($last_updated=="") {
	$jb->query("insert into jos_wp_content_import (last_record, total_records) Values(0, 0)");
 
	// If this is the first run, and the config is set to reset the content ID's (which is advised for SEO) then lets tyrn off Auto-increment
	// and we will reset it later on
	if($content_reset == "1") {
		$jb->query("ALTER TABLE `jos_content` CHANGE `id` `id` INT( 11 ) UNSIGNED NOT NULL ");
	}
}
 
// Lets start the dirty work and grab the first 50 records to insert, starting with the last updated.
// We are going to grab a lot of the fields, but not all and some of the ones we grab we may not use, but worth having just in case
$items = $db->get_results("Select ID, post_author, post_date, post_content, post_title, post_parent, post_excerpt, post_status, post_name, post_modified from ".$wp_prefix."posts where  ID>".$last_updated." and post_status='publish' or post_status='draft' order by ID ASC LIMIT ".$import_batch);
 
// a counter for our display math
$i=0;
//loop through the records and insert them into Joomla
foreach($items as $item) {
	// The very first thing we want to do is hit our function and get our new IDs so we can use them in the content inserts.
	$jos_ids = get_jos_ids($item->post_parent, $item->post_author);
 
	//Check if the item is published and if it is, then save it as published or draft
	if($item->post_status=="draft") {
		$post_status = "0";
	}
	else {
		$post_status = "1";
	}
 
	// Split the content on the <!--more--> tag so we have an "Intro text" and then re-assemble with {mospagebreak} instead (this just sets up the content in a neat way
	// We dont need to do it, but it's nice to be nice sometimes.
	$split_content = explode("<!--more-->", $item->post_content);
 
	foreach($split_content as $bound_content) {
		if($bound_content != $split_content[0]) {			
			$bound .= "{mospagebreak}".$bound_content;
		}
	}
	//Replace the first occurance of mospagebreak, as it will warp our pages
	$bound = preg_replace('/{mospagebreak}/', '', $bound, 1);
 
	//Check whether this is 1.5. or 1.0.x
	if($j_version=='1.5') {
		if($content_reset == 1) {
			$jb->query("insert into ".$j_prefix."content (id, title, alias, introtext, `fulltext`, state, sectionid, catid, created, created_by, modified) values(".$item->ID.", '".$item->post_title."', '".$item->post_name."', '".mysql_real_escape_string($split_content[0])."', '".mysql_real_escape_string($bound)."', '".$post_status."', ".$jos_ids["section"].", ".$jos_ids["category"].", '".$item->post_date."', ".$jos_ids["userid"].", '".$item->post_modified."')");
		}
		else {
			$jb->query("insert into ".$j_prefix."content (title, alias, introtext, `fulltext`, state, sectionid, catid, created, created_by, modified) values('".$item->post_title."', '".$item->post_name."', '".mysql_real_escape_string($split_content[0])."', '".mysql_real_escape_string($bound)."', '".$post_status."', ".$jos_ids["section"].", ".$jos_ids["category"].", '".$item->post_date."', ".$jos_ids["userid"].", '".$item->post_modified."')");
		}
	}
	else {
		if($content_reset == 1) {
			$jb->query("insert into ".$j_prefix."content (id, title, title_alias, introtext, `fulltext`, state, sectionid, catid, created, created_by, modified) values(".$item->ID.", '".$item->post_title."', '".$item->post_name."', '".mysql_real_escape_string($split_content[0])."', '".mysql_real_escape_string($bound)."', ".$post_status.", ".$jos_ids["section"].", ".$jos_ids["category"].", '".$item->post_date."', ".$jos_ids["userid"].", '".$item->post_modified."')");
 
 
		}
		else {
			$jb->query("insert into ".$j_prefix."content (title, title_alias, introtext, `fulltext`, state, sectionid, catid, created, created_by, modified) values('".$item->post_title."', '".$item->post_name."', '".mysql_real_escape_string($split_content[0])."', '".mysql_real_escape_string($bound)."', '".$post_status."', ".$jos_ids["section"].", ".$jos_ids["category"].", '".$item->post_date."', ".$jos_ids["userid"].", '".$item->post_modified."')");
		}
	}
 
 
	//
	// Update the last updated content item
	//
	$jb->query("update jos_wp_content_import set last_record=".$item->ID);
 
 
	//
	// Now we need to select out the comments for the post and insert them into the correct comment table.
	//
	if($import_comments=="1") {
		$comments = $db->get_results("select * from ".$wp_prefix."comments where comment_post_ID=".$item->ID." and comment_approved<>'spam' order by comment_ID");
		foreach($comments as $comment) {
			//
			// Retrieve the new userIDs
			//
			$j_user_id = get_jos_ids(0, $comment->user_id);
			if($j_user_id["userid"]=="") {
				$j_user_id["userid"]="0";
			}
			//check which comment component we are inserting into
			//we use a switch statement so that we can add to it later if we need to add other comment modules
			switch($jom_comment_mod) {
				case "1": 
					$jb->query("insert into ".$j_prefix."jomcomment (parentid, contentid, ip, comment, date, published, email, website, user_id) values(0, ".$item->ID.", '".$comment->comment_author_IP."', '".$comment->comment_content."', '".$comment->comment_date."', 1, '".$comment->comment_author_email."', '".$comment->comment_author_url."', ".$j_user_id["userid"].")");
				break;
				case "2":
 
					$jb->query("insert into ".$j_prefix."comment (contentid, ip, userid, date, email, website, comment, published, parentid, usertype) values(".$item->ID.", '".$comment->comment_author_IP."', ".$j_user_id["userid"].", '".$comment->comment_date."', '".$comment->comment_author_email."', '".$comment->comment_author_url."', '".$comment->comment_content."', 1, '-1', '')");
				break;
			}
 
			//Much the same as the category function, this is a recursive function to find sub-comments and insert them
			get_nested_comments($comment->comment_ID, $jb->insert_id, $item->ID);
		}
	}
	$i++;
 
}
 
// Add the count to our current count for UI
$imported_sofar = $jb->get_var("SELECT total_records from jos_wp_content_import");
 
// Update our count in the temp table for display and UI reasons
$imported_sofar += $i;
$jb->query("update jos_wp_content_import set total_records=".$imported_sofar);
 
// Do the full count
 
//
// Reset the content table to auto_increment
if($content_reset == "1") {
		$jb->query(" ALTER TABLE `jos_content` CHANGE `id` `id` INT( 11 ) UNSIGNED NOT NULL AUTO_INCREMENT");
}
 
?>
 
 
<?php
if($imported_sofar < $content_items){
?>
Imported <?= $imported_sofar;?> of <?= $content_items;?> so far
<form action="<?= $_SERVER['PHP_SELF']; ?>" method="post">
<input type="submit" name="submit" value="Continue to Next Step" />
</form>
<?php
}
else {
	echo "Import of Content and Comments complete. Now for the cleanup";
}
 
 
?>

I hope to have the fully GUI up and running package within the next few days. Please do no redistribute these files. They are for use on your own server, and for download from http://www.phpCoder.org only

Rate this:
2.1

3 Comments

Post a comment   |   Trackback URI   |   Comments RSS feed

  •  
    Marco

    Hi,

    Got this error:

    Warning: Table ‘jos_user_map’ already exists in /home/website/domains/website.com/public_html/wp2Joomla/db/ez_sql_mysql.php on line 204
    Created User Map table
    Selected WP Users and beginning insert loop

    ezSQL (v2.03) Debug..

    Last Error — [Table 'jos_user_map' already exists]

    what’s wrong?

  •  
    no image
    Dan (Who am I?)

    This means you have run the conversion once before. You should be able to continue without the application fatally failing, it is more a warning than a failure.

    However you may need to skip to the final step to remove the table or manually delete the table jos_user_map

    Was this a fresh Joomla install as well?

  •  
    Caryl

    Great Job !
    We’ve waited for a long time, and the K2 community for joomla will be, in my opinion, your next downloader !!!!

    So I’ve tried it and, after no problem with categories I’ve this error :


    Warning: Table ‘expatexc_joomla.wp_posts’ doesn’t exist in /home/expatexc/public_html/wp2Joomla/db/ez_sql_mysql.php on line 204

    Warning: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘and post_status=’publish’ or post_status=’draft’ order by ID ASC LIMIT 20′ at line 1 in /home/expatexc/public_html/wp2Joomla/db/ez_sql_mysql.php on line 204

    ezSQL (v2.03) Debug..

    Last Error — [You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'and post_status='publish' or post_status='draft' order by ID ASC LIMIT 20' at line 1]

    Query [1] — [Select ID, post_author, post_date, post_content, post_title, post_parent, post_excerpt, post_status, post_name, post_modified from wp_posts where ID> and post_status='publish' or post_status='draft' order by ID ASC LIMIT 20]

    Query Result..

    No Results”

    Could you help me ?
    (Just for your information My MySql Server is 5.0.77)

    Thanks you very much….

Trackbacks/Pings

  • No trackbacks or pings yet

Leave a Comment

Comment template by SezWho