-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Ryan Tyler
committed
Aug 5, 2011
0 parents
commit 1af74e8
Showing
12 changed files
with
3,659 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
This software is licensed under the terms described in the concrete5.org marketplace. Please find the add-on there for the latest license copy. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
Wordpress Importer does a basic import of a wordpress blog. | ||
The main idea is that someone can take their old content and have it represented on a concrete5 site. | ||
|
||
What it is doing: | ||
- Uses a wizard-like interface to import | ||
- Import is incremental -- keeps user in the loop and continues where it left off | ||
- Includes basic image import | ||
- Uses WP's own text formatting functions so everything comes through looking like a paragraph, etc | ||
|
||
Not so great: | ||
- pages and posts import under the same page | ||
- No "Start Over" on the first step. Choosing a new database when you have existing records doesn't do anything so the dialog shouldn't be there. | ||
- Not selecting a page to import under is very bad. Hundreds of pages show up under "home" and the link does not work at the WORDPRESSED step. | ||
- Should not proceed if "Posts" are going under Home. This basically ruins a site. | ||
- icon.png does not look good | ||
|
||
Would be nice: | ||
- Have an option to import "posts" under one page and "pages" under another. | ||
- Option to import just posts or just pages. | ||
- Include a new page type called "WordPress Post" that is basically the "Blog" page type but without the lipsum text. | ||
- some kind of rudimentary support for image captions, like <div class="wp-import-image"> <img /> <span class="wp-import-caption">caption</span></div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<?php defined('C5_EXECUTE') or die(_("Access Denied.")); | ||
|
||
class WordpressSiteImporterPackage extends Package { | ||
protected $pkgDescription = 'Add wordpress import capability to your site'; | ||
protected $pkgName = "WordPress Site Importer"; | ||
protected $pkgHandle = 'wordpress_site_importer'; | ||
|
||
protected $appVersionRequired = '5.3.3.1'; | ||
protected $pkgVersion = '1.0'; | ||
|
||
|
||
public function install() { | ||
|
||
$pkg = parent::install(); | ||
Loader::model('single_page'); | ||
$single_page = SinglePage::add('/dashboard/wordpress_import', $pkg); | ||
$single_page->update(array('cName' => 'WordPress Import', 'cDescription' => 'Import WordPress Sites')); | ||
|
||
$import_stuff = SinglePage::add('/dashboard/wordpress_import/site',$pkg); | ||
} | ||
} | ||
?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
<?php defined('C5_EXECUTE') or die(_("Access Denied.")); | ||
|
||
|
||
class DashboardWordpressImportController extends Controller{ | ||
public function view() { | ||
$db = Loader::db(); | ||
$records = $db->GetOne("select count(*) from WordpressItems where imported = 0"); | ||
$this->set('records',$records); | ||
} | ||
public function import_wordpress_xml() { | ||
if($this->post('import-images') == 'on'){ | ||
$this->importImages = true; | ||
$filesetname; | ||
($this->post('file-set-name')) ? $this->filesetname = $this->post('file-set-name') : $this->filesetname = t("Imported Wordpress Files") ; | ||
$this->createFileSet = true; | ||
} | ||
$pages = array(); | ||
|
||
if($this->post('wp-file') > 0) { | ||
Loader::model('file'); | ||
|
||
$importFile = File::getByID($this->post('wp-file')); | ||
$nv = $importFile->getVersion(); | ||
$fileUrl = $nv->getDownloadURL(); | ||
$xml = @simplexml_load_file($fileUrl); | ||
|
||
$items = array(); | ||
foreach($xml->channel->item as $item) { | ||
$items[] = $item->asxml(); | ||
} | ||
$db = Loader::db(); | ||
$sql = $db->Prepare('insert into WordpressItems (wpItem) values(?)'); | ||
|
||
foreach ($items as $item) { | ||
$db->Execute($sql,$item); | ||
} | ||
} else { | ||
echo t("No file"); | ||
exit; | ||
} | ||
$this->view(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,267 @@ | ||
<?php defined('C5_EXECUTE') or die(_("Access Denied.")); | ||
|
||
Loader::model('page_lite','wordpress_site_importer'); | ||
//something that would make this truly nice and almost 1:1 with a wordpress site would be to have a page for each "category" | ||
//basically that's the only thing this isn't doing aside from bringing in comments in some form. | ||
|
||
class DashboardWordpressImportSiteController extends Controller{ | ||
protected $fileset; | ||
protected $createdFiles = array(); | ||
protected $importImages = false; | ||
protected $importFiles; | ||
protected $filesetname = 'wp-stuff'; | ||
protected $createFileSet; | ||
|
||
function on_start(){ | ||
$cts = array(); | ||
Loader::model('collection_types'); | ||
$list = CollectionType::getList(); | ||
//this just lists out the page_types in concrete5, nothing hard | ||
foreach($list as $ct){ | ||
$cts[$ct->getCollectionTypeID()] = $ct->getCollectionTypeName(); | ||
} | ||
$this->set('collectiontypes',$cts); | ||
} | ||
|
||
public function get_root_page() { | ||
Loader::model('page'); | ||
$json = Loader::helper('json'); | ||
$data = array(); | ||
$rootPage = Page::getByID($this->post('new-root-wordpress')); | ||
$data['title'] = $rootPage->getCollectionName(); | ||
$data['url'] = $rootPage->getCollectionPath(); | ||
echo $json->encode($data); | ||
exit; | ||
} | ||
|
||
function import_wordpress_site(){ | ||
$db = Loader::db(); | ||
Loader::library('formatting','wordpress_site_importer'); | ||
$this->importImages = $this->post('import-images'); | ||
$this->createFileSet = $this->importImages; | ||
|
||
$unImported = $db->GetOne("SELECT COUNT(*) FROM WordpressItems where imported = 0"); | ||
if ($unImported > 0) { | ||
$data = array('remain'=>$unImported,'processed'=>'','titles'=>array()); | ||
|
||
$xml = $db->GetAll("SELECT wpItem,id FROM WordpressItems where imported = 0 LIMIT 10"); | ||
$data['processed'] = sizeof($xml); | ||
/* var_dump($xml); | ||
exit; | ||
*/ | ||
} else { | ||
echo 0; | ||
exit; | ||
} | ||
|
||
$ids = array(); | ||
foreach($xml as $wpItem){ | ||
|
||
libxml_use_internal_errors; | ||
$item = @new SimpleXMLElement($wpItem['wpItem']); | ||
|
||
$p = new PageLite(); | ||
|
||
//Use that namespace | ||
$title = (string)$item->title; | ||
$datePublic = $item->pubDate; | ||
$namespaces = $item->getNameSpaces(true); | ||
//Now we don't have the URL hard-coded | ||
|
||
$wp = $item->children($namespaces['wp']); | ||
$wpPostID = (int)$wp->post_id; | ||
$content = $item->children($namespaces['content']); | ||
$content = wpautop((string)$content->encoded); | ||
/* | ||
find the caption in the caption. | ||
replace [caption ... with <div class="wp-caption-frame"> //alternatively there should be a custom image template that creates a caption. | ||
that might be the more c5 way to do this. | ||
then [/caption] with the image and then <span class="wp-caption-text">$caption_text</span></div> | ||
??? | ||
*/ | ||
/* | ||
comments... | ||
Can't figure out why this is not working for the comments. | ||
*/ | ||
/* $comments = $wp->comment->asXML(); | ||
var_dump($comments); | ||
var_dump($comments->asXML()); | ||
//echo $comments->asXML(); | ||
exit;*/ | ||
$excerpt = $item->children($namespaces['excerpt']); | ||
$postDate = (string)$wp->post_date; | ||
$postType = (string)$wp->post_type; | ||
$dc = $item->children($namespaces['dc']); | ||
$author = (string)$dc->creator; | ||
$parentID = (int)$wp->post_parent; | ||
$category = (string)$item->category; | ||
|
||
$p->setTitle($title); | ||
$p->setContent($content); | ||
$p->setAuthor($author); | ||
$p->setWpParentID($parentID); | ||
$p->setPostDate($postDate); | ||
$p->setPostType($postType); | ||
$p->setCategory($category); | ||
$p->setPostID($wpPostID); | ||
$p->setExcerpt($excerpt); | ||
|
||
//so we just throw these guys in an array | ||
$pages[$p->getPostID()] = $p; //postID is unique | ||
$ids[] = $wpItem['id']; | ||
$data['titles'][] = $title; | ||
|
||
} | ||
//call the function below | ||
$this->buildSiteFromWordPress($pages); | ||
|
||
$db->Execute('UPDATE WordpressItems set imported=1 where id in('.implode(',',$ids).')'); | ||
$json = Loader::helper('json'); | ||
echo $json->encode($data); | ||
exit; | ||
|
||
//foreach ($xml->id as $id) | ||
//idarray | ||
//delete or set imported | ||
|
||
} | ||
|
||
|
||
function buildSiteFromWordPress(array $pages){ | ||
Loader::model('page'); | ||
//this creates the fileset and sets it as a protected property of this controller class so we can reference it without throwing these defines around, i'll get rid of em | ||
//eventually | ||
if($this->createFileSet){ | ||
Loader::model('file_set'); | ||
$fs = new FileSet(); | ||
$u = new User(); | ||
$uID = User::getUserID(); | ||
$newFs = FileSet::createAndGetSet($this->filesetname, 1,$uID); | ||
$this->fileset = $newFs; | ||
} | ||
|
||
|
||
|
||
$errors = array(); | ||
//$message = ''; | ||
//get our root page | ||
$rootPage = Page::getByID($this->post('new-root-wordpress')); | ||
//this is how / where to set another page for page-type pages. | ||
|
||
//ok so basically our keys in our array are wordpress postIDs, which are pages in the system | ||
//so what we need to do now (thinking here) is that we need to arrange these posts into a tree | ||
//$pages is in the format of the postID => pageLiteObject | ||
Loader::model('collection_types'); | ||
$ctPagesID = CollectionType::getByID($this->post('wordpress-pages')); | ||
$ctBlogID = CollectionType::getByID($this->post('wordpress-blogs')); | ||
//we want to reference the collection type we are adding based on either a post or a page | ||
$collectionTypesForWordpress = array("POST"=>$ctBlogID,"PAGE"=>$ctPagesID); | ||
|
||
$parentIDPageLiteRel = array(); | ||
$createdPages = array(); | ||
$createdPagesReal = array(); | ||
|
||
$fakeCreatedPages = array(); | ||
//so our homepage is zero, and we need that in our created page, even though it isn't a page that is created for association issues but it absolutely has to be 0. | ||
//Then it is a relational mapping issue, this puppy took a bit of thought | ||
// | ||
$createdPagesReal[0] = $rootPage; | ||
//so foreach pages | ||
foreach($pages as $pageLite){ | ||
$ct = $collectionTypesForWordpress[$pageLite->getPostType()]; | ||
|
||
|
||
//create the pages | ||
//right now i am only handling posts and pages, we have to ignore attachments as they are posted elsewhere or referenced in posts or pages | ||
if(is_a($ct,CollectionType)){ | ||
$createdPagesReal[$pageLite->getPostID()] = $this->addWordpressPage($rootPage, $ct, $pageLite); | ||
//here's how we map our pages to pages | ||
$parentIDPageLiteRel[$pageLite->getWpParentID()][] = $pageLite->getPostID(); | ||
}else{ | ||
//this is kind of spooky and frustrating to see. | ||
$errors[] = t("Un-supported post type for post - ").$pageLite->getTitle(); | ||
} | ||
} | ||
//so right here basically all we do is move the kid page right under the parent page. what is cool about concrete5 is that you don't need any sort of | ||
//order or anything, pages can be added under pages and it is all just figured out here rather elegantly | ||
foreach($parentIDPageLiteRel as $parentID => $kids){ | ||
if(is_array($kids) && count($kids)){ | ||
//move our pages to whatever is specified | ||
foreach($kids as $pageThatNeedsMoved){ | ||
$createdPagesReal[$pageThatNeedsMoved]->move($createdPagesReal[$parentID]); | ||
} | ||
} | ||
} | ||
$this->set('message',t('Wordpress Export Imported under ').$rootPage->getCollectionName()); | ||
$this->set('errors',$errors); | ||
} | ||
|
||
|
||
// this function takes a page as an arguement, the collection type and a page-lite object. | ||
function addWordpressPage(Page $p, CollectionType $ct, PageLite $pl){ | ||
/* echo $pl->getPostdate(); | ||
exit; | ||
*/ | ||
$pageData = array('cName' => $pl->getTitle(),'cDatePublic'=>$pl->getPostdate(),'cDateAdded'=>$pl->getPostdate(),'cDescription' => $pl->getExcerpt()); | ||
$newPage = $p->add($ct,$pageData); | ||
Loader::model('block_types'); | ||
$bt = BlockType::getByHandle('content'); | ||
$data = array(); | ||
|
||
$data['content'] = ($this->importImages) ? $this->determineImportableMediaFromContent($pl->getContent(),$pageData) : $pl->getContent(); //we're either importing images or not | ||
$newPage->addBlock($bt, "Main", $data); | ||
return $newPage; | ||
} | ||
|
||
|
||
function determineImportableMediaFromContent($content,$pageData){ | ||
/* | ||
After looking at how wordpress actually does this I was completely wrong. This is actually working ok but could probably use some sprucing up. | ||
*/ | ||
|
||
//TODO: continually revisit this regex; | ||
$pattern = '/<a href="([^"]*)"><img.*(?:title="([^"]*)")? src="([^"]*)".*\/><\/a>/'; | ||
$matches = array(); | ||
if(preg_match_all($pattern,$content,$matches)){ | ||
Loader::library('wordpress_file_post_importer','wordpress_site_importer'); | ||
Loader::model('file'); | ||
//get how many potential file matches we have here | ||
//match all fills an array so we iternate node 0 which is the match then get use that node as a key to access the rest | ||
$count = 0; | ||
$matchedFiles = array(); | ||
foreach($matches[0] as $key => $value){ | ||
$matchesFiles[$key] = array('thumb' => $matches[3][$key], 'main'=> $matches[1][$key],'fullMatch'=>$matches[0][$key]); | ||
//print_r matches if you need to see how it works | ||
} | ||
foreach($matchesFiles as $mfers){ //at this point the variable name made sense | ||
$tBase = basename($mfers['thumb']); | ||
$mBase = basename($mfers['main']); | ||
|
||
if(array_key_exists($tBase,$this->createdFiles) && is_a($this->createdFiles[$tBase],'FileVersion')){ | ||
$thumbFile = $this->createdFiles[$tBase]; | ||
}else{ | ||
$thumbFile = WordpressFileImporter::importFile($mfers['thumb']); | ||
$this->createdFiles[$tBase] = $thumbFile; | ||
} | ||
if(array_key_exists($mBase,$this->createdFiles) && is_a($this->createdFiles[$mBase],'FileVersion')){ | ||
$fullFile = $this->createdFiles[$mBase]; | ||
}else{ | ||
$fullFile = WordpressFileImporter::importFile($mfers['main']); | ||
$this->createdFiles[$mBase] = $fullFile; | ||
} | ||
if($thumbFile instanceof FileVersion && $fullFile instanceof FileVersion){ | ||
$this->fileset->addFileToSet($thumbFile); | ||
$this->fileset->addFileToSet($fullFile); | ||
$thumbID = $thumbFile->getFileID(); | ||
$mainID = $fullFile->getFileID(); | ||
$replacement = '<a href="{CCM:FID_'.$mainID.'}"><img src="{CCM:FID_'.$thumbID.'}" alt="'.$fullFile->getTitle().'" title="'.$fullFile->getTitle().'" /></a>'; | ||
//replace the matched one with what we want. | ||
$content = str_replace($mfers['fullMatch'],$replacement,$content); | ||
} | ||
} | ||
} | ||
|
||
return $content; | ||
} | ||
} | ||
?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<?xml version="1.0"?> | ||
<schema version="0.3"> | ||
<table name="WordpressItems"> | ||
<field name="id" type="I" size="11"> | ||
<NOTNULL/> | ||
<KEY/> | ||
<AUTOINCREMENT/> | ||
</field> | ||
<field name="wpItem" type="longtext"> | ||
<NOTNULL/> | ||
</field> | ||
<field name="imported" type="tinyint" size="1"> | ||
<NOTNULL/> | ||
<default value="0"/> | ||
</field> | ||
</table> | ||
</schema> |
Oops, something went wrong.