Subscribe

Drupal Multigroup Migration to ExpressionEngine

Written by in Technology
on

A client has a Drupal site that we’re migrating to ExpressionEngine. It’s a decently-sized site, with articles in multiple languages, and using the Drupal 6 CCK Multigroup Module. The Multigroup module for Drupal is a lot like the Matrix addon for ExpressionEngine; it pretty much allows you to create repeatable field groups.

  The Multigroup module has been discontinued, with the Field Collection module taking its place.

  The client was using Multigroup to handle images in their content articles. A content article has some number of text blocks with some number of images between each text block. Each element in the multigroup has a WYSIWYG field and a image field, with a dropdown that indicates whether the image should come before or after the text block.

  Of course, I didn’t know any of this going in. I figured I’d do a simple database dump and use the ajw_datagrab module to import the content into EE. There’s a guide by 9seeds that explains how to migrate Drupal content to WordPress with a few simple queries. The resulting database dump can be imported with Datagrab, so this was the basis for the first query I wrote:

  [sql]
SELECT DISTINCT
n.nid `id`,
n.language `lang`,
FROM_UNIXTIME(n.created) `post_date`,
r.body `post_content`,
n.title `post_title`,
r.teaser `post_excerpt`,
IF(SUBSTR(a.dst, 11, 1) = ‘/’, SUBSTR(a.dst, 12), a.dst) `post_name`,
FROM_UNIXTIME(n.changed) `post_modified`,
n.type `post_type`,
IF(n.STATUS = 1, ‘publish’, ‘private’) `post_status`
FROM node n
INNER JOIN node_revisions r
USING(vid)
LEFT OUTER JOIN url_alias a
ON a.src = CONCAT(‘node/’, n.nid)
WHERE n.type IN (‘post’, ‘page’, ‘article’)
[/sql]

  The content that this query returned seemed a bit sparse, but not really having a full understanding of the content that was supposed to have been output, I figured I was done. The lead developer on the project knew better and introduced me to the tables in the backend where additional content was stored, and the content fields these tables corresponded to in the Drupal backend.

  The database tables I looked at were:
content_field_art_img (which stored the references to the image IDs),
content_field_art_pos (which stored the position of the image field relative to the text blocks), and
content_field_art_txt (which stored the text blocks).

  The next step was to grab the content from these tables and put it into some workable format.

  Each of the three tables has a `nid` and `delta` column. The `nid` column relates the content in these tables to a particular node. The `delta` was less obvious at first, though I was able to correctly guess that it represented the order of the text/image blocks.

  I could either write a complex query to JOIN all the tables together, but I would have still had a bunch of deltas I needed to concatenate, so I took three big dumps (output as PHP arrays via phpMyAdmin) and made PHP clean up the mess.

  [sql]
SELECT c.nid,c.delta,f.filepath as imgsrc FROM content_field_art_img c, files f WHERE c.field_art_img_fid = f.fid ORDER BY c.nid ASC, c.delta ASC
SELECT nid, delta, field_art_txt_value FROM content_field_art_txt ORDER BY nid ASC, delta ASC
SELECT nid, delta, field_art_pos_value FROM content_field_art_pos ORDER BY nid ASC, delta ASC
[/sql]

  The next step was to combine the content into a one big array indexed by nid and delta:

  [php]
foreach ($content_field_art_img as $img) {
$content[$img['nid']][$img['delta']]['img'] = $img['imgsrc'];
}
foreach ($content_field_art_txt as $txt) {
$content[$txt['nid']][$txt['delta']]['txt'] = $txt['field_art_txt_value'];
}
foreach ($content_field_art_pos as $pos) {
$content[$pos['nid']][$pos['delta']]['pos'] = $pos['field_art_pos_value'];
}
[/php]

  Then I went through the array and concatenated the pos, txt, and img for each delta, then each node, storing the node content for each node id.

  [php]
$combined_content = array();
foreach ($content as $nid => $node) {
$the_content = ""
foreach ($node as $delta) {
if (isset($delta['pos']) && $delta['pos'] == "above") {
if (isset($delta['img']) && !empty($delta['img'])) {
$the_content .= "\n</pre>
<img src="\&quot;/{$delta['img']}\&quot;” alt=”” />
<pre>

  “;
}
if (isset($delta[‘txt’]) && !empty($delta[‘txt’])) {
$the_content .= "\n" . $delta['txt'];
}
} else {
if (isset($delta['txt']) && !empty($delta['txt'])) {
$the_content .= "\n" . $delta['txt'];
}
if (isset($delta[‘img’]) && !empty($delta[‘img’])) {
$the_content .= "\n</pre>
<img src="\&quot;/{$delta['img']}\&quot;” alt=”” />
<pre>

  “;
}
}
}
$combined_content[$nid] = $the_content;
}
[/php]

  And then output the $combined_content as one big PHP array, which the lead could then import into EE.

  [php]
echo “// \n\$combined_content = “;
var_export($combined_content);
[/php]

  Needless to say, everything worked and everyone was happy. This solution may not be the most efficient way to export the data but it does the job intended.

Get more insights right to your inbox.

Email