Exporting & Importing Members in ExpressionEngine

I recently acquired a client with an existing ExpressionEngine site. The site build was quite old and in need of an overhaul for a number of reasons. After consulting with the client it was determined the best approach would be to do a complete rebuild of the site which would enable a more modern and efficient approach to the site build.

The issue was how to import data from the old site to the new site. Importing blog entries was easy using the Datagrab module but importing members was not as strait forward. Importing members itself is not difficult as there is a member import utitlity, however exporting members out of ExpressionEngine into the correct format is not well documented. 

I chose to import from XML but there are no ExpressionEngine tags that will output all the members. Fortunately I was in the EE Slack Chat and Derek Jones of EllisLab instructed me to use the query module.

My final xml templateis below. I had xml errors until I added CDATA around the salt variable. Also Note that there is an extra space in the variable. Without the extra space my blog rendered the email tag.

1
2
3
4
5
6
7
8
9
10
11
12
13
<members>
&#123;exp:query sql="SELECT username, password, salt, email, url, bio, screen_name FROM exp_members"&#125;
	<member>
		<username></username>
		<screen_name></screen_name>
		<password type="sha1">{password}</password>
		<salt><![CDATA[{salt}]]></salt>
		<email>{ email}</email>
		<url>{url}</url>
		<bio><![CDATA[{bio}]]></bio>
	</member>
&#123;/exp:query&#125;
</members>

Next upload the xml file on the new server and run the import utility at Tools > Utilities > Import Tool 

SASS Variable for Image Path

I'm building out a new site in Statamic which is my go to CMS for smaller sites that don't all the power that ExpressionEngine or CraftCMS have to offer. With Statamic your images, css, and javascript files are required to be in specific folders. This is not an issue except that I'm a lazy typer.

In my sites I usually keep images in a folder at root so that all I need to type is /images/file_name.jpg and it works. However images are required to be in /_themes/theme_name/img/ which is a whole lot longer to type and I know I'll have typos. My solution was to set a variable 

1
$imgpath: /_themes/etf/img;

And then in the relevant css have this:

1
2
3
header {
	background: url($imgpath/hero-image.jpg) no-repeat left bottom;
}

That however resulted in errors.

1
Error: Invalid CSS after \"...path/hero-image\": expected \")\", was \".jpg) no-repeat...\

The solution is to code the variable slightly different when putting it in a path by adding curly braces around it and a proceeding pound sign like this:

1
2
3
header {
	background: url(#{$imgpath}/hero-image.jpg) no-repeat left bottom;
}

Much easier to write out and remember than the full path to the image folder.

ExpressionEngine, Structure and Bootstrap Navbar

Two agencies that I regularly do ExpressionEngine work require that the Structure Module is used in the builds. I've become quite proficient with Structure, but still prefer to build sites without it and do so when I have the option.

One of the issues I have with Structure is that the navigation tag is difficult to work with especially if you are using a framework such as Foundation or Bootstrap when building your sites. The structure nav tag doesn't allow for the customization of the HTML that is needed when using Bootstrap or Foundation. What I've done in the past is hard code the main nav items and use multiple Structure nav tags for the dropdowns. It works but isn't very efficient.

By adding a little javascript I can now use a single structure nav tag, have working dropdowns and allow the client to reorder the navigation at will.

My Navbar HTML looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<div class="navbar-wrapper">
  <div class="container">
    <div class="navbar navbar-static-top" role="navigation">
      <div class="container">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="/">Site Name</a>
        </div>
        <div class="navbar-collapse collapse">  
          {exp:structure:nav 
            start_from ="/" 
            current_class="active" 
            max_depth="3"
            show_depth="3"
            css_class="nav navbar-nav navbar-right"
          }
        </div>
      </div>
    </div>
  </div>
</div>

All we need is a little jquery to get this to work correctly.

1
2
3
4
5
6
7
8
// make structure play nice with bootstrap dropdown navs
$( document ).ready(function() {
	//add dropdown class if li contains ul and data-toggle to link
	$('.navbar ul.navbar-nav li:has(ul)').addClass('dropdown').find('> a').addClass('dropdown-toggle').attr('data-toggle', 'dropdown');
 
	//add dropdown-menu to nested ul
	$('.navbar ul.navbar-nav li > ul').addClass('dropdown-menu');
});

Migrating Content from ExpressionEngine to Craft

I've wanted to give Craft CMS a go for a while now and figured the best way to do it is with a personal project. My photo blog is in dire need or a revamp and as such I've decided to migrate to Craft. Installing Craft is dead easy and took only about 90 seconds including time to download the zip file.

Before I started working on the design I wanted to be sure that I would be able to easily migrate four years of content so the first step was migrating my Entries. This turned out to be relatively painless with the use of this import plugin.

I first copied all photos from the live site to my upload folder of the new site. Then in the Craft CP click the gear icon on the top right, then Assets, New source and fill in the fields. both the path and url can be set to relative paths, but be sure to not use a leading slash. After saving click the gear icon again and go to the lower left and update asset indexes. A short time later all your images are in the database. You can confirm this by clicking on Assets in the nav.

The next step is to install the Import plugin by putting the files in /craft/plugins then in the CP click gear and plugins and finally install. This plugin only imports content in CSV format. This requires a new template in ExpressionEngine which will need to be set wiht php turned on in order to force the browser to download the file directly.

The php at the top of the template tells the browser this is an excel file and forces it to download the file on browser load

1
2
3
4
5
6
<?php
    header("Content-type: application/vnd.ms-excel");
header("Content-Disposition: attachment; filename=photoblog-export.xls");
header("Pragma: no-cache");
header("Expires: 0");
?>

The next bit of code contains all our fields and how we want them named. This is important to easily map the fields using the import plugin. Line 20 has entry_date with extra spaces this is due to my blog rendering it and not displaying the code correctly - remove extra spaces for it to work. When migrating images, be sure to only include the image name. My images currently reside in a Matrix field {photos} and a file cell. In order to get just the file name it is necessary to use the file tag pair like this {image}{file_name}{/image} where the outer tag pair is the file field/cell name.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<table>
<tbody>
<tr>
   <td>Title</td>
    <td>Url Title</td>
    <td>Entry Date</td>
    <td>Description</td>
    <td>Image</td>
</tr>
{exp:channel:entries channel='photoblog' limit='500' disable="categories|member_data|pagination|comments" status="not foo"}
    <tr>
            <td>Migrating Content from ExpressionEngine to Craft</td>
            <td>{url_title}</td>
            <td>{ entry_date }</td>
            <td>{description}</td>
            <td>{photos}{image}{file_name}{/image}{/photos}</td>
    </tr>
{/exp:channel:entries}
</tbody>

After downloading the file open it in Excel, you may see a warning that the file format doesn't match the extension, open it anyhow. Now do a save as and choose CSV (comma delimited). My research indicated that this extra step is necessary as using the template to save as CSV with content that contains quotes may not work correctly.

Now to import, click Import in the Nav. Fill in the fields as required and upload your CSV file.

Go to the next page where we map the fields to Craft fields. 

Now hit import, wait a few minutes and all of your entries will be imported. To confirm click on "Entries" in the top nav.  Assuming that new content is added to the live site before this build is finished then all you need to do to update is do a new export with only the new entries since the last import and repeat the process. Super easy.

Now it's time to start templating the new site.

Comment Update

Joe sent me an email in response to his my comment below - commenting is turned off automatically after a couple of weeks for spam protection. I've copied his comment here:

 Hi, just replying to my comment on your article: Migrating Content from
ExpressionEngine to Craft. I couldn't make another comment on the article
for some reason.

Anyway, I was able to import my images finally. I actually used the Feed Me
plugin (https://github.com/engram-design/FeedMe) Very similar to Import, but
it allows for XML which is super nice. And to get the images from EE Matrix
to map to Craft Assets field, I just had to separate them with a comma in
the XML.  That part of the EE template looked like this:

1
2
3
4
<images>
<![CDATA[{project-images
backspace="1"}{image}{file_name},{/image}{/project-images}]]>
</images>

Your Voice Here
Leave a Comment