Generate Flat Wordpress Files

Instead of serving Wordpress over PHP, I decided to sync only the static files to the webserver. This results in increased security since the admin interface is not available on the server. The page loads are also very fast since the pages are static and don't have to process anything or hit the database.

NOTE: My workflow has changed. I’m now using Jekyll and Amazon S3.

Before proceeding, it’s always a good idea to backup data. By migrating, the code and database will be duplicated locally as intermediary steps. The Wordpress install needs to be downloaded to your target destination, and a SQL database dump of Wordpress is necessary. Although I don’t explicitly indicate to do so, saving the results of these intermediary steps will help with restoration if needed. Nothing is deleted from the original server until the final steps.

Some features will be unavailable. Wordpress comments will be unusable, but an external comment system like Disqus can be used instead. Some features like XML-RPC won’t be usable at the original host, but if you can access the original Wordpress install, you should be able to use it.

Migrating Your Installation

Before beginning, you should look into Disqus or whichever comment service you will be using to see if there are ways to export your comments. I didn’t have Wordpress comments turned on, so I didn’t have to worry about migrating comments. I’ve quickly searched Google and it seems like there are options to migrate comments. I didn’t actually go through the process, but if you don’t export comments now, it may become much more difficult later. If anyone goes through this process, please let me know and I’ll provide a link here.

I didn’t look for any migration tutorials, so a better solution most likely exists. I decided to do the transition in the most logical manner: copy the files and the database. I copied the files by downloading to the local directory for my web server, /Users/jongyulin/Sites/wordpress/ (I use OS X). My host has phpMyAdmin, so I generated a MySQL dump of my Wordpress database using phpMyAdmin.

Depending on the settings used to generate the dump, existing databases will either be dropped or generate an existing database error preventing the import. For simplicity, don’t import a database with a name that already exists. If you’re unsure what the import will do, open dump.sql in your favorite text editor and take a quick look through it, searching for key phrases like “CREATE DATABASE” will make the quick look less tedious. A SQL file is a script of successive SQL queries recreating the dumped database. Making changes is simply a matter of modifying the queries in the text file.

Once satisfied that my SQL dump wasn’t going to do anything bad, I imported the database, created a user to access it, and manually updated my Wordpress settings. From the command–line:

mysql -u root -p < dump.sql
mysql -u root -p
mysql> GRANT ALL PRIVILEGES ON wpdatabase.* TO user@localhost IDENTIFIED BY password;
mysql> USE wpdatabase
mysql> UPDATE wp_options SET option_value="http://localhost/~jongyulin/wordpress" WHERE option_name="siteurl" OR option_name="home" LIMIT 2;

The first line imports the MySQL dump from the server into your database. The last MySQL UPDATE command is necessary to make the site work, because the administrative sections (wp-admin/) will attempt to redirect to the value associated with siteurl.

Your Wordpress settings now need to match the local database installation. If they are different than the original installation, you’ll have to modify the following lines in wp-config.php:

define(DB_NAME, 'wpdatabase');
define('DB_USER', 'user');
define('DB_PASSWORD', 'password');
define('DB_HOST', 'localhost');

Permalinks

Permalinks may not work if the Apache configuration is not setup for mod_rewrite. Going over every reason for mod_rewrite not working is outside the scope of this guide since the reason can vary. I will go into what I did to get mod_rewrite to work, but my Apache install has been around for awhile. I’m sure I’ve tinkered with the configuration files many times. The most important recommendation is to look at the Apache error logs. For me, on OS X, the log files are located at /private/var/log/apache2/.

Getting mod_rewrite to work on my local system involved changing AllowOverride from None to All in /private/etc/apache2/httpd.conf in <Directory />, and making the same change in /private/etc/apache2/users/jongyulin.conf. I also had to add FollowSymLinks in the Options line. If I had “Options Indexes,” it became “Options FollowSymLinks Indexes.” The log files were very helpful in figuring out I was missing FollowSymLinks.

Since my original Wordpress install was in the root directory and my new location is in a sub–directory, I had to update the .htaccess files to make Permalinks work. Log–in to the administrative CMS, go to Settings -> Permalinks. At the bottom of the page, you should see the contents for the .htaccess files. Replace the existing .htaccess file in your root directory. I copied the contents into /Users/jongyulin/Sites/wordpress/.htaccess.

Comments

Disqus was not too difficult to setup. After going through registration, I reached the page with installation instructions. I chose “Universal Code” and copied the corresponding script in the locations I wanted. For the display script, I placed it right before the end of my post div in single.php (located in your themes directory). I placed the end script in footer.php like so:

 
<?php
  if(is_single()):

?>
    <script type="text/javascript">
      // javascript code here
    </script>
<?php
  endif;

?>
 

Generating the Flat Files and Synchronizing with the Remote Server

I created a PHP script to go through all the commands I wanted. I really should make it into a simple shell script, but I’ve been working so much in PHP, I reached for it out of habit.

 
// create flat files
system('wget --mirror -p --html-extension --convert-links http://localhost/~jongyulin/wordpress');
 
// replace any stray URL instances

system('find localhost -type f -print | xargs sed -i .bck \'s/http:\/\/localhost\/~jongyulin\/wordpress/http:\/\/www.jongyulin.com/g\'');

 
// remove backup files created by sed
system('find localhost -name "*.bck" | xargs rm');
 
// Repeat for possible escaped URLs
system('find localhost -type f -print | xargs sed -i .bck \'s/http:\/\/localhost\/%7Ejongyulin\/wordpress/http:\/\/www.jongyulin.com/g\'');

system('find localhost -name "*.bck" | xargs rm');
 
// One last check
system('grep -r localhost localhost/*');
 

The script may need some modification if your source and target directories are different.

Wget doesn’t seem to change the URLs in the RSS and Atom feeds (might be missing a switch), which is why I have two calls to find / sed. In general, it’s probably a good idea to check and try to replace anyway. The last check is a very generic search that will probably generate false positives, such as this post, but I wanted to be sure to catch anything that may seem amiss.

I place the php script where I wanted everything to download (/Users/jongyulin/Sites/wordpress_static/) and ran it from the command–line:

cd directory_for_download
create script in this directory
php import.php

I didn’t want to automate the rsync until after I could verify the results, mainly that the final grep didn’t return anything that looked wrong. The last command to finish it all up is an rsync. Please note running this command will replace the Wordpress install on the host with your own flat files. It would be handy to have a backup of the host in case things go awry. I would also recommend doing a dry run without --delete. The source and target directories must be correct or bad you may suffer from unintended actions, especially with delete enabled:

cd /Users/jongyulin/Sites/wordpress_static/localhost/~jongyulin/
rsync -avz --delete ./ -e ssh username@server.com:/var/www

All the files on your host are now flat Wordpress files. Anytime you need to update, simply re–run the script and rsync the new files.

blog comments powered by Disqus