MIGRATING IVF-EMBRYO.GR FROM JOOMLA! TO DRUPAL
ivf-embryo.gr is Thanos Paraschos' "Embio Medical Center" website. Embio Medical Center is a specialized in vitro fertilisation clinic.
The clinic is one of the most known in Greece and its website is one of the largest in both in content and visitor numbers that was developed and hosted by Netstudio. We joke about it calling it an encyclopedia due to the tremendous amount of articles it contains.
The website was developed in 2007 using Joomla! 1.0.x and in 2009 was transferred to Joomla! 1.5.x. During those 4 years, and while the content's volume was still growing, 2 major reconstructions needed to be done along with numerous fixes and improvements.
Having already witnessed Drupal's advantages over Joomla! (faster loading, solid platform, SEO optimized, expandable), we chose to convert ivf-embryo.gr into a Drupal site. That proved to be way harder than we had anticipated.
The site comprised a staggering 550 elements in its main menu, already translated in 8 languages! The menu was linked to over 4500 pages and also included contact forms, videos, images with enlargement capabilities etc. Also, the whole moving process needed to include precise url migrations (meaning the old joomla! urls should match exactly the new ones) so the site wouldn't lose its ranking in the search engines.
For this project, 5 out of 9 members of our team had to participate and also a partner from the clinic's side. Initially, Yannis installed and set Drupal and the basic modules that we would need. After that, I took up the actual process of moving the content.
Initially, I tried using Drupal Feeds. I succesfully added a large percentage of the content this way by matching Joomla! articles to Drupal nodes. Sadly, at that part, the site's internationalization features kicked in to ruin everything. I had to intervene in Feeds' code in order to extend it and make it support the needs of the particular case. Since time was an issue, I didn't have the luxury to develop a module that would extend Feeds, so I wrote a module from scratch that performed the basic operations we needed. That proved to be more time efficient since we didn't meddle with the multiple cases Feeds is designed to deal with.
Here is a code snipet, using the Drupal API for inserting a Basic page and its translation:
<span style="color: #000000"><span style="color: #0000BB"><?php<br></span><span style="color: #007700">global </span><span style="color: #0000BB">$user</span><span style="color: #007700">;<p></p></span><span style="color: #FF8000">// joomla ID<br></span><span style="color: #0000BB">$joomla_id </span><span style="color: #007700">= </span><span style="color: #0000BB">15</span><span style="color: #007700">;<p></p></span><span style="color: #FF8000">// Choose the node that fits the Joomla ID.<br>// Having already created a field_joomla_id<br></span><span style="color: #0000BB">$query </span><span style="color: #007700">= new </span><span style="color: #0000BB">EntityFieldQuery</span><span style="color: #007700">;<br></span><span style="color: #0000BB">$results </span><span style="color: #007700">= </span><span style="color: #0000BB">$query</span><span style="color: #007700">-></span><span style="color: #0000BB">entityCondition</span><span style="color: #007700">(</span><span style="color: #DD0000">'entity_type'</span><span style="color: #007700">, </span><span style="color: #DD0000">'node'</span><span style="color: #007700">)<br> -></span><span style="color: #0000BB">propertyCondition</span><span style="color: #007700">(</span><span style="color: #DD0000">'language'</span><span style="color: #007700">, </span><span style="color: #DD0000">'el'</span><span style="color: #007700">)<br> -></span><span style="color: #0000BB">fieldCondition</span><span style="color: #007700">(</span><span style="color: #DD0000">'field_joomla_id'</span><span style="color: #007700">, </span><span style="color: #DD0000">'value'</span><span style="color: #007700">, </span><span style="color: #0000BB">$joomla_id</span><span style="color: #007700">, </span><span style="color: #DD0000">'='</span><span style="color: #007700">)-></span><span style="color: #0000BB">execute</span><span style="color: #007700">();<p></p></span><span style="color: #FF8000">// Array holding node translations<br></span><span style="color: #0000BB">$ex_translations </span><span style="color: #007700">= array();<p></p></span><span style="color: #FF8000">// If the node already exists update it<br></span><span style="color: #007700">if(!empty(</span><span style="color: #0000BB">$results</span><span style="color: #007700">)){<br> </span><span style="color: #0000BB">$nid </span><span style="color: #007700">= </span><span style="color: #0000BB">current</span><span style="color: #007700">(</span><span style="color: #0000BB">$results</span><span style="color: #007700">[</span><span style="color: #DD0000">'node'</span><span style="color: #007700">])-></span><span style="color: #0000BB">nid</span><span style="color: #007700">;<br> </span><span style="color: #0000BB">$newnode </span><span style="color: #007700">= </span><span style="color: #0000BB">node_load</span><span style="color: #007700">(</span><span style="color: #0000BB">$nid</span><span style="color: #007700">);<br> </span><span style="color: #0000BB">$tnid </span><span style="color: #007700">= </span><span style="color: #0000BB">$newnode</span><span style="color: #007700">-></span><span style="color: #0000BB">tnid</span><span style="color: #007700">;<br> </span><span style="color: #0000BB">$ex_translations </span><span style="color: #007700">= </span><span style="color: #0000BB">translation_node_get_translations</span><span style="color: #007700">(</span><span style="color: #0000BB">$tnid</span><span style="color: #007700">);<br>}<p></p></span><span style="color: #FF8000">// Else create a new one<br></span><span style="color: #007700">else{<br> </span><span style="color: #0000BB">$newnode </span><span style="color: #007700">= new </span><span style="color: #0000BB">stdClass</span><span style="color: #007700">();<br>}<p></p></span><span style="color: #0000BB">$newnode</span><span style="color: #007700">-></span><span style="color: #0000BB">language </span><span style="color: #007700">= </span><span style="color: #DD0000">'el'</span><span style="color: #007700">;<br></span><span style="color: #0000BB">$newnode</span><span style="color: #007700">-></span><span style="color: #0000BB">type </span><span style="color: #007700">= </span><span style="color: #DD0000">'page'</span><span style="color: #007700">;<br></span><span style="color: #0000BB">$newnode</span><span style="color: #007700">-></span><span style="color: #0000BB">name </span><span style="color: #007700">= </span><span style="color: #0000BB">$user</span><span style="color: #007700">-></span><span style="color: #0000BB">name</span><span style="color: #007700">;<br></span><span style="color: #0000BB">$newnode</span><span style="color: #007700">-></span><span style="color: #0000BB">title </span><span style="color: #007700">= </span><span style="color: #DD0000">'Greek Titme'</span><span style="color: #007700">;<br></span><span style="color: #0000BB">$newnode</span><span style="color: #007700">-></span><span style="color: #0000BB">body</span><span style="color: #007700">[</span><span style="color: #0000BB">$newnode</span><span style="color: #007700">-></span><span style="color: #0000BB">language</span><span style="color: #007700">][</span><span style="color: #0000BB">0</span><span style="color: #007700">][</span><span style="color: #DD0000">'summary'</span><span style="color: #007700">] = </span><span style="color: #DD0000">''</span><span style="color: #007700">;<br></span><span style="color: #0000BB">$newnode</span><span style="color: #007700">-></span><span style="color: #0000BB">body</span><span style="color: #007700">[</span><span style="color: #0000BB">$newnode</span><span style="color: #007700">-></span><span style="color: #0000BB">language</span><span style="color: #007700">][</span><span style="color: #0000BB">0</span><span style="color: #007700">][</span><span style="color: #DD0000">'value'</span><span style="color: #007700">] = </span><span style="color: #DD0000">'Greek content'</span><span style="color: #007700">;<br></span><span style="color: #0000BB">$newnode</span><span style="color: #007700">-></span><span style="color: #0000BB">body</span><span style="color: #007700">[</span><span style="color: #0000BB">$newnode</span><span style="color: #007700">-></span><span style="color: #0000BB">language</span><span style="color: #007700">][</span><span style="color: #0000BB">0</span><span style="color: #007700">][</span><span style="color: #DD0000">'format'</span><span style="color: #007700">] = </span><span style="color: #DD0000">'full_html'</span><span style="color: #007700">;<br></span><span style="color: #0000BB">$newnode</span><span style="color: #007700">-></span><span style="color: #0000BB">field_joomla_id</span><span style="color: #007700">[</span><span style="color: #0000BB">LANGUAGE_NONE</span><span style="color: #007700">][</span><span style="color: #0000BB">0</span><span style="color: #007700">][</span><span style="color: #DD0000">'value'</span><span style="color: #007700">] = </span><span style="color: #0000BB">$joomla_id</span><span style="color: #007700">;<p></p></span><span style="color: #FF8000">// prepare the node for saving<br></span><span style="color: #0000BB">$newnode </span><span style="color: #007700">= </span><span style="color: #0000BB">node_submit</span><span style="color: #007700">(</span><span style="color: #0000BB">$newnode</span><span style="color: #007700">);<p></p></span><span style="color: #FF8000">// save the node<br></span><span style="color: #0000BB">node_save</span><span style="color: #007700">(</span><span style="color: #0000BB">$newnode</span><span style="color: #007700">);<p></p></span><span style="color: #FF8000">// For translations, tnid needs to be set<br></span><span style="color: #007700">if(empty(</span><span style="color: #0000BB">$ex_translations</span><span style="color: #007700">)){<br> </span><span style="color: #0000BB">db_update</span><span style="color: #007700">(</span><span style="color: #DD0000">'node'</span><span style="color: #007700">)<br> -></span><span style="color: #0000BB">fields</span><span style="color: #007700">(array(<br> </span><span style="color: #DD0000">'tnid' </span><span style="color: #007700">=> </span><span style="color: #0000BB">$newnode</span><span style="color: #007700">-></span><span style="color: #0000BB">nid</span><span style="color: #007700">,<br> </span><span style="color: #DD0000">'translate' </span><span style="color: #007700">=> </span><span style="color: #0000BB">0</span><span style="color: #007700">,<br> ))<br> -></span><span style="color: #0000BB">condition</span><span style="color: #007700">(</span><span style="color: #DD0000">'nid'</span><span style="color: #007700">, </span><span style="color: #0000BB">$newnode</span><span style="color: #007700">-></span><span style="color: #0000BB">nid</span><span style="color: #007700">)<br> -></span><span style="color: #0000BB">execute</span><span style="color: #007700">();<br>}<p></p></span><span style="color: #FF8000">// If translations already exist, update them<br></span><span style="color: #007700">if(!empty(</span><span style="color: #0000BB">$ex_translations</span><span style="color: #007700">)){<br> </span><span style="color: #0000BB">$tnode </span><span style="color: #007700">= </span><span style="color: #0000BB">node_load</span><span style="color: #007700">(</span><span style="color: #0000BB">$ex_translations</span><span style="color: #007700">[</span><span style="color: #DD0000">'en'</span><span style="color: #007700">]-></span><span style="color: #0000BB">nid</span><span style="color: #007700">);<br>}<br></span><span style="color: #FF8000">// Else create new ones<br></span><span style="color: #007700">else{<br> </span><span style="color: #0000BB">$tnode </span><span style="color: #007700">= new </span><span style="color: #0000BB">StdClass</span><span style="color: #007700">();<br>}<p></p></span><span style="color: #0000BB">$tnode</span><span style="color: #007700">-></span><span style="color: #0000BB">type </span><span style="color: #007700">= </span><span style="color: #DD0000">'page'</span><span style="color: #007700">;<br></span><span style="color: #0000BB">$tnode</span><span style="color: #007700">-></span><span style="color: #0000BB">uid </span><span style="color: #007700">= </span><span style="color: #0000BB">$user</span><span style="color: #007700">-></span><span style="color: #0000BB">uid</span><span style="color: #007700">;<br></span><span style="color: #0000BB">$tnode</span><span style="color: #007700">-></span><span style="color: #0000BB">title </span><span style="color: #007700">= </span><span style="color: #DD0000">'Translated Title'</span><span style="color: #007700">;<br></span><span style="color: #0000BB">$tnode</span><span style="color: #007700">-></span><span style="color: #0000BB">language </span><span style="color: #007700">= </span><span style="color: #DD0000">'en'</span><span style="color: #007700">;<br></span><span style="color: #0000BB">$tnode</span><span style="color: #007700">-></span><span style="color: #0000BB">body</span><span style="color: #007700">[</span><span style="color: #0000BB">$tnode</span><span style="color: #007700">-></span><span style="color: #0000BB">language</span><span style="color: #007700">][</span><span style="color: #0000BB">0</span><span style="color: #007700">][</span><span style="color: #DD0000">'summary'</span><span style="color: #007700">] = </span><span style="color: #DD0000">''</span><span style="color: #007700">;<br></span><span style="color: #0000BB">$tnode</span><span style="color: #007700">-></span><span style="color: #0000BB">body</span><span style="color: #007700">[</span><span style="color: #0000BB">$tnode</span><span style="color: #007700">-></span><span style="color: #0000BB">language</span><span style="color: #007700">][</span><span style="color: #0000BB">0</span><span style="color: #007700">][</span><span style="color: #DD0000">'value'</span><span style="color: #007700">] = </span><span style="color: #DD0000">'Translated Content'</span><span style="color: #007700">;<br></span><span style="color: #0000BB">$tnode</span><span style="color: #007700">-></span><span style="color: #0000BB">body</span><span style="color: #007700">[</span><span style="color: #0000BB">$tnode</span><span style="color: #007700">-></span><span style="color: #0000BB">language</span><span style="color: #007700">][</span><span style="color: #0000BB">0</span><span style="color: #007700">][</span><span style="color: #DD0000">'format'</span><span style="color: #007700">] = </span><span style="color: #DD0000">'full_html'</span><span style="color: #007700">;<br></span><span style="color: #0000BB">$tnode</span><span style="color: #007700">-></span><span style="color: #0000BB">field_joomla_id</span><span style="color: #007700">[</span><span style="color: #0000BB">LANGUAGE_NONE</span><span style="color: #007700">][</span><span style="color: #0000BB">0</span><span style="color: #007700">][</span><span style="color: #DD0000">'value'</span><span style="color: #007700">] = </span><span style="color: #0000BB">$joomla_id</span><span style="color: #007700">;<br></span><span style="color: #0000BB">$tnode</span><span style="color: #007700">-></span><span style="color: #0000BB">promote </span><span style="color: #007700">= </span><span style="color: #0000BB">1</span><span style="color: #007700">;<br>if(empty(</span><span style="color: #0000BB">$tnode</span><span style="color: #007700">-></span><span style="color: #0000BB">tnid</span><span style="color: #007700">)){<br> </span><span style="color: #0000BB">$tnode</span><span style="color: #007700">-></span><span style="color: #0000BB">tnid </span><span style="color: #007700">= </span><span style="color: #0000BB">$newnode</span><span style="color: #007700">-></span><span style="color: #0000BB">nid</span><span style="color: #007700">;<br>}<p></p></span><span style="color: #FF8000">// Saved translation<br></span><span style="color: #0000BB">node_save</span><span style="color: #007700">(</span><span style="color: #0000BB">$tnode</span><span style="color: #007700">);<br></span><span style="color: #0000BB">?></span></span>
On the other side (Joomla!), a component was created that extracted in json format the corresponding information.
<span style="color: #000000"><span style="color: #0000BB"><?php<br>$db </span><span style="color: #007700">= </span><span style="color: #0000BB">JFactory</span><span style="color: #007700">::</span><span style="color: #0000BB">getDBO</span><span style="color: #007700">();<p></p></span><span style="color: #0000BB">$q </span><span style="color: #007700">= </span><span style="color: #DD0000">"<br>SELECT c.id, c.title, c.introtext, c.fulltext, c.created FROM #__content AS c<br>WHERE state = 1<br>ORDER BY c.id<br>"</span><span style="color: #007700">;<p></p></span><span style="color: #0000BB">$db</span><span style="color: #007700">-></span><span style="color: #0000BB">setQuery</span><span style="color: #007700">(</span><span style="color: #0000BB">$q</span><span style="color: #007700">);<br></span><span style="color: #0000BB">$articles </span><span style="color: #007700">= </span><span style="color: #0000BB">$db</span><span style="color: #007700">-></span><span style="color: #0000BB">loadObjectList</span><span style="color: #007700">();<p></p></span><span style="color: #0000BB">$export </span><span style="color: #007700">= array();<p>foreach(</p></span><span style="color: #0000BB">$articles </span><span style="color: #007700">as </span><span style="color: #0000BB">$i</span><span style="color: #007700">=></span><span style="color: #0000BB">$a</span><span style="color: #007700">){<br> </span><span style="color: #0000BB">$export</span><span style="color: #007700">[</span><span style="color: #0000BB">$i</span><span style="color: #007700">][</span><span style="color: #DD0000">'id'</span><span style="color: #007700">] = </span><span style="color: #0000BB">$a</span><span style="color: #007700">-></span><span style="color: #0000BB">id</span><span style="color: #007700">;<br> </span><span style="color: #0000BB">$export</span><span style="color: #007700">[</span><span style="color: #0000BB">$i</span><span style="color: #007700">][</span><span style="color: #DD0000">'title'</span><span style="color: #007700">] = </span><span style="color: #0000BB">$a</span><span style="color: #007700">-></span><span style="color: #0000BB">title</span><span style="color: #007700">;<br> </span><span style="color: #0000BB">$export</span><span style="color: #007700">[</span><span style="color: #0000BB">$i</span><span style="color: #007700">][</span><span style="color: #DD0000">'introtext'</span><span style="color: #007700">] = </span><span style="color: #0000BB">$a</span><span style="color: #007700">-></span><span style="color: #0000BB">introtext</span><span style="color: #007700">;<br> </span><span style="color: #0000BB">$export</span><span style="color: #007700">[</span><span style="color: #0000BB">$i</span><span style="color: #007700">][</span><span style="color: #DD0000">'fulltext'</span><span style="color: #007700">] = </span><span style="color: #0000BB">$a</span><span style="color: #007700">-></span><span style="color: #0000BB">fulltext</span><span style="color: #007700">;<br> </span><span style="color: #0000BB">$export</span><span style="color: #007700">[</span><span style="color: #0000BB">$i</span><span style="color: #007700">][</span><span style="color: #DD0000">'date'</span><span style="color: #007700">] = </span><span style="color: #0000BB">$a</span><span style="color: #007700">-></span><span style="color: #0000BB">created</span><span style="color: #007700">;<br> </span><span style="color: #0000BB">$export</span><span style="color: #007700">[</span><span style="color: #0000BB">$i</span><span style="color: #007700">][</span><span style="color: #DD0000">'redirect'</span><span style="color: #007700">] = </span><span style="color: #0000BB">JRoute</span><span style="color: #007700">::</span><span style="color: #0000BB">_</span><span style="color: #007700">(</span><span style="color: #DD0000">'index.php?option=com_content&view=article&id='</span><span style="color: #007700">.</span><span style="color: #0000BB">$a</span><span style="color: #007700">-></span><span style="color: #0000BB">id</span><span style="color: #007700">);<br>}<br>echo </span><span style="color: #0000BB">json_encode</span><span style="color: #007700">(</span><span style="color: #0000BB">$export</span><span style="color: #007700">);<br></span><span style="color: #0000BB">?></span></span>
That json string was passed into Drupal where the the module we wrote performed the necessary operations in order to create the menus, nodes and translations accordingly and insert them into the database (using the Drupal API of course). The whole process was long and tiresome. After many (many) attempts, many staging servers restores, many words and phrases that for censorship issues Ι will ommit from this text, and many "yiipee's" after the successes, Ι managed to complete the transfer. The information was transferred with great precision and very little needed to be corrected manually.
The next issue we needed to tackle was images. They were manually added in Drupal's "files" folder (where they would normally be saved by Drupal). Then, another module was created who's job was to deal with the display of the images using lightbox and dynamically generate thumbnails.
Last but not least, I was left with the url matching. Fortunatelly, here the solution was rather obvious. We used Drupal Redirect (http://drupal.org/project/redirect) and chose to redirect instead of copying the paths. The reason is that Drupal handles urls brilliantly with pathauto and we wanted it to stay that way.
That's where my part ended. George made the last correction on the blocks and menus while Olga performed corrections and revisions on the content. Lastly, Panagiotis who manages our clients' Google campaigns, had to alter the landing pages' urls in the ad texts.
Finally, the website runs on Drupal! You can visit it at http://www.ivf-embryo.gr. It's faster than ever since it uses Drupal 7 caching. Everyone here at Netstudio and most importantly the client are very pleased with the migration and we can already see the positive outcome from the better ranking in Google's results!