Skip to content

Commit

Permalink
Adding initial 1.0 version
Browse files Browse the repository at this point in the history
  • Loading branch information
Ryan Tyler committed Aug 5, 2011
0 parents commit 1af74e8
Show file tree
Hide file tree
Showing 12 changed files with 3,659 additions and 0 deletions.
1 change: 1 addition & 0 deletions LICENSE.TXT
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.
21 changes: 21 additions & 0 deletions README
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>
22 changes: 22 additions & 0 deletions controller.php
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);
}
}
?>
43 changes: 43 additions & 0 deletions controllers/dashboard/wordpress_import/controller.php
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();
}
}
267 changes: 267 additions & 0 deletions controllers/dashboard/wordpress_import/site.php
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;
}
}
?>
17 changes: 17 additions & 0 deletions db.xml
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>
Binary file added icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 1af74e8

Please sign in to comment.