Skip to content
Snippets Groups Projects
Commit 1982f79a authored by Mike Ryan's avatar Mike Ryan
Browse files

Issue #2259751 by mikeryan: First stab at leveraging Migrate new namespace support

parent 328a1ab3
No related tags found
No related merge requests found
......@@ -319,6 +319,9 @@ class WordPressBlog {
* The raw WXR file as uploaded.
* @param $destination
* Filespec to which to write the cleaned-up WXR file.
*
* @return array
* List of referenced namespaces, keyed by prefix.
*/
static public function preprocessFile($sourcefile, $destination) {
// Cleanup some stuff in the process of moving the file to its final
......@@ -353,6 +356,12 @@ class WordPressBlog {
$itunes_ns = 'xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"';
$header = str_replace($content_ns, $itunes_ns . "\n\t" . $content_ns, $header);
preg_match_all('|xmlns:(.+?)="(.+?)"|i', $header, $matches, PREG_SET_ORDER);
$namespaces = array();
foreach ($matches as $index => $match) {
$namespaces[$match[1]] = $match[2];
}
// Replace HTML entities with XML entities
$header = strtr($header, self::$entityReplacements);
fputs($dest_handle, $header);
......@@ -374,6 +383,8 @@ class WordPressBlog {
fclose($dest_handle);
fclose($source_handle);
unlink($sourcefile);
return $namespaces;
}
/**
......
......@@ -60,13 +60,13 @@ class WordPressAttachment extends WordPressMigration {
MigrateDestinationFile::getKeySchema()
);
$this->addFieldMapping('value', 'attachment_url');
$this->addFieldMapping('destination_file', 'attachment_url')
$this->addFieldMapping('value', 'wp:attachment_url');
$this->addFieldMapping('destination_file', 'wp:attachment_url')
->callbacks(array($this, 'fixDestinationFile'));
$this->addFieldMapping('uid', 'creator')
$this->addFieldMapping('uid', 'dc:creator')
->description('Use matching username if any, otherwise current user');
$this->addFieldMapping('timestamp', 'post_date');
$this->addFieldMapping(NULL, 'post_parent')
$this->addFieldMapping('timestamp', 'wp:post_date');
$this->addFieldMapping(NULL, 'sp:post_parent')
->description('Mapping is handled dynamically');
// Unmapped destination fields
......@@ -74,14 +74,14 @@ class WordPressAttachment extends WordPressMigration {
'file_replace', 'preserve_files', 'source_dir'));
// Unmapped source fields
$this->addUnmigratedSources(array('link', 'guid', 'description', 'excerpt',
'post_id', 'comment_status', 'ping_status', 'post_name', 'status',
'menu_order', 'post_type', 'post_password', 'is_sticky', 'tag', 'category',
'_wp_attached_file', '_wp_attachment_metadata', 'title', 'content'));
$this->addUnmigratedSources(array('link', 'guid', 'description', 'excerpt:encoded',
'wp:post_id', 'wp:comment_status', 'wp:ping_status', 'wp:post_name', 'wp:status',
'wp:menu_order', 'wp:post_type', 'wp:post_password', 'wp:is_sticky', 'tag', 'category',
'_wp_attached_file', '_wp_attachment_metadata', 'title', 'content:encoded'));
$this->addFieldMapping(NULL, 'pubDate')
->description('Use post_date')
->issueGroup(t('DNM'));
$this->addFieldMapping(NULL, 'post_date_gmt')
$this->addFieldMapping(NULL, 'wp:post_date_gmt')
->description('Use post_date')
->issueGroup(t('DNM'));
}
......
......@@ -29,12 +29,12 @@ class WordPressAuthor extends WordPressMigration {
);
$fields = array(
'author_id' => 'Unique WordPress ID of the author',
'author_login' => 'Username (for login) of the author',
'author_email' => 'Author email address',
'author_display_name' => 'Displayed author name',
'author_first_name' => 'Author first name',
'author_last_name' => 'Author last name',
'wp:author_id' => 'Unique WordPress ID of the author',
'wp:author_login' => 'Username (for login) of the author',
'wp:author_email' => 'Author email address',
'wp:author_display_name' => 'Displayed author name',
'wp:author_first_name' => 'Author first name',
'wp:author_last_name' => 'Author last name',
);
// Construct the source and destination objects.
......@@ -43,13 +43,13 @@ class WordPressAuthor extends WordPressMigration {
'cache_counts' => TRUE,
);
$this->source = new WordPressSourceXML($this->wxrFile, '/rss/channel/wp:author',
'wp:author_login', $fields, $source_options);
'wp:author_login', $fields, $source_options, $this->arguments['namespaces']);
$this->destination = new WordPressAuthorDestination($arguments);
// The basic mappings
$this->addFieldMapping('name', 'author_login')
$this->addFieldMapping('name', 'wp:author_login')
->dedupe('users', 'name');
$this->addFieldMapping('mail', 'author_email');
$this->addFieldMapping('mail', 'wp:author_email');
$this->addFieldMapping('roles')
->defaultValue(DRUPAL_AUTHENTICATED_RID);
$this->addFieldMapping('status')
......@@ -64,8 +64,8 @@ class WordPressAuthor extends WordPressMigration {
}
// Unmapped source fields
$this->addUnmigratedSources(array('author_display_name', 'author_first_name',
'author_last_name', 'author_id'));
$this->addUnmigratedSources(array('wp:author_display_name', 'wp:author_first_name',
'wp:author_last_name', 'wp:author_id'));
}
}
......
......@@ -43,13 +43,13 @@ class WordPressCategory extends WordPressMigration {
'cache_counts' => TRUE,
);
$this->source = new WordPressSourceXML($this->wxrFile, '/rss/channel/category',
'wp:category_nicename', $fields, $source_options);
'wp:category_nicename', $fields, $source_options, $this->arguments['namespaces']);
$this->destination = new MigrateDestinationTerm($this->arguments['category_vocabulary']);
// The basic mappings
$this->addFieldMapping('name', 'cat_name');
$this->addFieldMapping('description', 'category_description');
$this->addFieldMapping('parent', 'category_parent')
$this->addFieldMapping('name', 'wp:cat_name');
$this->addFieldMapping('description', 'wp:category_description');
$this->addFieldMapping('parent', 'wp:category_parent')
->sourceMigration($this->machineName);
// Unmapped destination fields
......
......@@ -132,19 +132,19 @@ class WordPressComment extends WordPressMigration {
);
$fields = array(
'post_id' => 'Unique ID of the item the comment is attached to',
'comment_id' => 'Unique ID of the comment',
'comment_author' => 'Name of comment author',
'comment_author_email' => 'Email address of comment author',
'comment_author_url' => 'URL of comment author',
'comment_author_IP' => 'IP address from which comment was posted',
'comment_date' => 'Date of comment (what timezone?)',
'comment_date_gmt' => 'Date of comment (GMT)',
'comment_content' => 'Body of comment',
'comment_approved' => '1/0/spam - spam comments will not be imported',
'comment_type' => '?',
'comment_parent' => 'comment_id (?) of parent comment',
'comment_user_id' => 'WordPress user ID of commenter (?)',
'wp:post_id' => 'Unique ID of the item the comment is attached to',
'wp:comment_id' => 'Unique ID of the comment',
'wp:comment_author' => 'Name of comment author',
'wp:comment_author_email' => 'Email address of comment author',
'wp:comment_author_url' => 'URL of comment author',
'wp:comment_author_IP' => 'IP address from which comment was posted',
'wp:comment_date' => 'Date of comment (what timezone?)',
'wp:comment_date_gmt' => 'Date of comment (GMT)',
'wp:comment_content' => 'Body of comment',
'wp:comment_approved' => '1/0/spam - spam comments will not be imported',
'wp:comment_type' => '?',
'wp:comment_parent' => 'comment_id (?) of parent comment',
'wp:comment_user_id' => 'WordPress user ID of commenter (?)',
);
$source_options = array(
......@@ -152,44 +152,44 @@ class WordPressComment extends WordPressMigration {
'cache_counts' => TRUE,
);
$this->source = new WordPressSourceXML($this->wxrFile, '/rss/channel/item/comment',
'wp:comment_id', $fields, $source_options);
'wp:comment_id', $fields, $source_options, $this->arguments['namespaces']);
$this->destination = new MigrateDestinationComment('comment_node_' . $arguments['post_type']);
// The basic mappings
$this->addFieldMapping('nid', 'post_id')
$this->addFieldMapping('nid', 'wp:post_id')
->sourceMigration($this->arguments['dependencies']);
$this->addFieldMapping('pid', 'comment_parent')
$this->addFieldMapping('pid', 'wp:comment_parent')
->sourceMigration($this->generateMachineName('WordPressComment'));
$this->addFieldMapping('uid')
->description('Use email to match Drupal account; if no match, default to anonymous');
$this->addFieldMapping('subject')
->description('No comment subjects in WP')
->issueGroup('DNM');
$this->addFieldMapping('hostname', 'comment_author_IP');
$this->addFieldMapping('created', 'comment_date');
$this->addFieldMapping('changed', 'comment_date');
$this->addFieldMapping(NULL, 'comment_date_gmt')
$this->addFieldMapping('hostname', 'wp:comment_author_IP');
$this->addFieldMapping('created', 'wp:comment_date');
$this->addFieldMapping('changed', 'wp:comment_date');
$this->addFieldMapping(NULL, 'wp:comment_date_gmt')
->description('Using comment_date')
->issueGroup('DNM');
$this->addFieldMapping('status', 'comment_approved')
$this->addFieldMapping('status', 'wp:comment_approved')
->description('Do not import those with values of "spam"');
$this->addFieldMapping('thread')
->issueGroup('DNM');
$this->addFieldMapping('name', 'comment_author')
$this->addFieldMapping('name', 'wp:comment_author')
->callbacks(array($this, 'truncateName'));
$this->addFieldMapping('mail', 'comment_author_email');
$this->addFieldMapping('homepage', 'comment_author_url');
$this->addFieldMapping('mail', 'wp:comment_author_email');
$this->addFieldMapping('homepage', 'wp:comment_author_url');
$this->addFieldMapping('language');
$this->addFieldMapping(NULL, 'comment_id')
$this->addFieldMapping(NULL, 'wp:comment_id')
->description('Source primary key')
->issueGroup('DNM');
$this->addFieldMapping(NULL, 'comment_user_id')
$this->addFieldMapping(NULL, 'wp:comment_user_id')
->description('Always 0?')
->issueGroup('DNM');
$this->addFieldMapping(NULL, 'comment_type')
$this->addFieldMapping(NULL, 'wp:comment_type')
->description('Always empty?')
->issueGroup('DNM');
$this->addFieldMapping('comment_body', 'comment_content');
$this->addFieldMapping('comment_body', 'wp:comment_content');
$this->addFieldMapping('comment_body:format')
->defaultValue($arguments['text_format_comment']);
$this->addFieldMapping('comment_body:language');
......
......@@ -52,14 +52,15 @@ class WordPressItemSource extends WordPressSourceXML {
* Simple initialization.
*
*/
public function __construct($filename, $post_type, $cache_key) {
public function __construct($filename, $post_type, $cache_key, $namespaces = array()) {
$source_options = array(
'reader_class' => 'WordPressXMLReader',
'cache_counts' => TRUE,
'cache_key' => $cache_key,
);
drush_print_r($namespaces);
parent::__construct($filename, '/rss/channel/item', 'wp:post_id',
$this->fields, $source_options);
$this->fields, $source_options, $namespaces);
$this->postType = $post_type;
}
......@@ -71,8 +72,10 @@ class WordPressItemSource extends WordPressSourceXML {
foreach ($this->sourceUrls as $url) {
$reader = new $this->readerClass($url, $this->elementQuery, $this->idQuery);
foreach ($reader as $element) {
// drush_print_r($element);
// Only count relevant postType
if ($element->post_type == $this->postType) {
$field = 'wp:post_type';
if ($element->$field == $this->postType) {
$count++;
}
}
......@@ -147,34 +150,34 @@ abstract class WordPressItemMigration extends WordPressMigration {
);
// Construct the source objects.
$this->source = new WordPressItemSource($this->wxrFile, $this->postType, $this->machineName);
$this->source = new WordPressItemSource($this->wxrFile, $this->postType, $this->machineName, $this->arguments['namespaces']);
$this->destination = new MigrateDestinationNode($bundle);
// Default mappings, applying to most or all migrations
$this->addFieldMapping('title', 'title');
$this->addFieldMapping('created', 'post_date')
$this->addFieldMapping('created', 'wp:post_date')
->description('Empty dates handled in prepare()');
$this->addFieldMapping('changed', 'post_date')
$this->addFieldMapping('changed', 'wp:post_date')
->description('Empty dates handled in prepare()');
// If we have a separate author migration, use it here
$uid_mapping = $this->addFieldMapping('uid', 'creator')
$uid_mapping = $this->addFieldMapping('uid', 'dc:creator')
->description('Use matching username if any, otherwise current user');
if ($this->blog->getWxrVersion() != '1.0') {
$uid_mapping->sourceMigration($this->group->getName() . 'Author');
}
$this->addFieldMapping('body', 'content');
$this->addFieldMapping('body:summary', 'excerpt');
$this->addFieldMapping('body', 'content:encoded');
$this->addFieldMapping('body:summary', 'excerpt:encoded');
$this->addFieldMapping('body:format')
->defaultValue($this->arguments['text_format']);
if (module_exists('comment')) {
$this->addFieldMapping('comment', 'comment_status')
$this->addFieldMapping('comment', 'wp:comment_status')
->description('WP "open" mapped to Drupal COMMENT_NODE_OPEN');
}
$this->addFieldMapping('status', 'status')
$this->addFieldMapping('status', 'wp:status')
->description('Set Drupal status to 1 iff wp:status=publish');
$this->addFieldMapping(NULL, 'post_parent')
$this->addFieldMapping(NULL, 'wp:post_parent')
->description('Only applies to attachments');
$this->addFieldMapping('sticky', 'is_sticky');
$this->addFieldMapping('sticky', 'wp:is_sticky');
if (module_exists('path')) {
switch ($this->arguments['path_action']) {
// Do not set path aliases
......@@ -257,7 +260,7 @@ abstract class WordPressItemMigration extends WordPressMigration {
'promote', 'revision_uid', 'log', 'tnid', 'translate', 'body:language'));
// Unmapped source fields
$this->addUnmigratedSources(array('post_id', 'menu_order', 'post_type'));
$this->addUnmigratedSources(array('wp:post_id', 'wp:menu_order', 'wp:post_type'));
$this->addFieldMapping(NULL, 'guid')
->description('same as link, plus isPermaLink attribute?')
->issueGroup(t('DNM'));
......@@ -267,17 +270,17 @@ abstract class WordPressItemMigration extends WordPressMigration {
$this->addFieldMapping(NULL, 'pubDate')
->description('Use post_date')
->issueGroup(t('DNM'));
$this->addFieldMapping(NULL, 'post_date_gmt')
$this->addFieldMapping(NULL, 'wp:post_date_gmt')
->description('Use post_date')
->issueGroup(t('DNM'));
$this->addFieldMapping(NULL, 'ping_status')
$this->addFieldMapping(NULL, 'wp:ping_status')
->description('What does this mean?')
->issueGroup(t('Open issues'))
->issuePriority(MigrateFieldMapping::ISSUE_PRIORITY_MEDIUM);
$this->addFieldMapping(NULL, 'post_name')
$this->addFieldMapping(NULL, 'wp:post_name')
->description('Looks like last component of path')
->issueGroup(t('DNM'));
$this->addFieldMapping(NULL, 'post_password')
$this->addFieldMapping(NULL, 'wp:post_password')
->description('???')
->issueGroup(t('DNM'));
}
......@@ -453,13 +456,15 @@ abstract class WordPressItemMigration extends WordPressMigration {
// Attempt to parse embedded media automatically through the media module.
try {
$uri = media_parse_to_uri($src);
if ($uri) {
// Sometimes, at least with oembed, it doesn't like the /v/ form
$uri = str_replace('youtube.com/v/', 'youtube.com/watch?v=', $uri);
}
}
catch (Exception $e) {
return $result;
}
if (!isset($uri)) {
if (empty($uri)) {
return $result;
}
......
......@@ -33,6 +33,13 @@ class WordPressMigrateWizard extends MigrateUIWizard {
protected $contentValues = array();
/**
* List of namespaces referenced by the WXR file, keyed by prefix.
*
* @var array
*/
protected $namespaces = array();
/**
* Lay out the basic steps of the wizard.
*/
......@@ -259,7 +266,7 @@ class WordPressMigrateWizard extends MigrateUIWizard {
}
}
WordPressBlog::preprocessFile($tmpfile, $this->filename);
$this->namespaces = WordPressBlog::preprocessFile($tmpfile, $this->filename);
// Only include the author step if we have author data (which was introduced
// in WXR 1.1)
......@@ -628,6 +635,7 @@ class WordPressMigrateWizard extends MigrateUIWizard {
$this->groupArguments = array(
'filename' => $this->filename,
'source_system' => $this->getSourceName(),
'namespaces' => $this->namespaces,
);
$message = t('<p>Please review your migration configuration. When you submit this
......
......@@ -12,7 +12,9 @@ class WordPressXMLReader extends MigrateXMLReader {
* @return void
*/
public function next() {
$this->registerNamespaces($this->currentElement);
parent::next();
return;
if (is_a($this->currentElement, 'SimpleXMLElement')) {
$item = $this->currentElement;
$currentRow = new stdClass;
......@@ -61,6 +63,18 @@ class WordPressXMLReader extends MigrateXMLReader {
$this->currentElement = $currentRow;
}
}
/**
* Explicitly register namespaces on an XML element.
*
* @param SimpleXMLElement $xml
* A SimpleXMLElement to register the namespaces on.
*/
protected function registerNamespaces(SimpleXMLElement &$xml) {
foreach ($this->namespaces as $prefix => $namespace) {
$xml->registerXPathNamespace($prefix, $namespace);
}
}
}
/**
......
......@@ -31,9 +31,9 @@ class WordPressTag extends WordPressMigration {
);
$fields = array(
'tag_slug' => 'Unique "machine name" of the tag',
'tag_name' => 'User-friendly tag name',
'tag_description' => 'Description of tag',
'wp:tag_slug' => 'Unique "machine name" of the tag',
'wp:tag_name' => 'User-friendly tag name',
'wp:tag_description' => 'Description of tag',
);
// Construct the source and destination objects.
......@@ -42,12 +42,12 @@ class WordPressTag extends WordPressMigration {
'cache_counts' => TRUE,
);
$this->source = new WordPressSourceXML($this->wxrFile, '/rss/channel/tag',
'wp:tag_slug', $fields, $source_options);
'wp:tag_slug', $fields, $source_options, $this->arguments['namespaces']);
$this->destination = new MigrateDestinationTerm($arguments['tag_vocabulary']);
// The basic mappings
$this->addFieldMapping('name', 'tag_name');
$this->addFieldMapping('description', 'tag_description');
$this->addFieldMapping('name', 'wp:tag_name');
$this->addFieldMapping('description', 'wp:tag_description');
$this->addFieldMapping('parent_name')
->issueGroup('DNM');
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment