How to Rebuild Your WordPress Website Like a Pro

How to Rebuild Your WordPress Website Like a Pro

There comes a time in the lifecycle of every website when a rebuild is unavoidable. The reasons vary; perhaps the original code is not very good, perhaps a complete visual overhaul is needed, perhaps a ton of new features are being added, or perhaps your site has been hacked.

Whatever the case may be, ample planning is needed to ensure the quality of the rebuild and smoothness of the transition.

In this article I’ll explore one way of doing things, something I have applied to a recent project with great success. I’ll also share some specific ways I work, not just “the theory,” so hopefully it will give you something to try out right away so you can create your own way of working.

Let’s get started.

The Steps of a Major Rebuild

Rebuilding a website is almost like creating a new one – just more complex. Not only do you have to make everything from scratch, you also have to make sure all the old systems are migrated correctly.

Note that throughout this article I’ll be considering a rebuild to be a complete ground-up job. If your original code is well-written you may be able to re-use a bunch of classes or functions.

Let’s look at a broad overview of the steps taken and then drill down into each:

  • Familiarize yourself with the project
  • Define requirements based on the project plan
  • Create a coding plan
  • Complete the coding tasks
  • Clean up and migrate the database
  • Test and finalize

I will not look at the design process separately, I’ll assume you have a ready design.

Familiarize Yourself With the Project

I cannot overstate the importance of this step. One of the reasons my rebuild project was successful – and other coders are successful when creating a website – is that I understood the website really well.

I don’t just mean the mechanical workings like knowing how the sidebar and header works. You should be familiar with the goals and the motivations of the website. You should know what they want to achieve, and more importantly, why.

The “why” is the most important aspect because it allows you to give intelligent advice throughout the process. Your advice may go against the initial ideas of the website owners, but if you can explain your views, aligning it with the ultimate goals of the website, you may yet add something to the discussion.

You will be able to make better decisions throughout the coding process, writing code that supports the ethos of the website, instead of code that simply works. This will make your efforts future-proof, and the client will get a bigger bang for their buck.

In my most recent rebuild this was easy. I’ve been involved in the project for five or so years now and I’m on very good terms with the owner. I knew what the website did, how it did it, why it did it, and why it no longer worked well. Not all of us are so lucky.

So what can you do if you arrive without any prior knowledge?

Use the Website

Get to know the project from a user’s point of view. Don’t look for potential problems. If the website is a store for information try finding something. If the site is a shop, try ordering something. You get the idea. Lack of prior knowledge can actually be a big advantage. You get to experience the website as a new user without any preconceptions, misconceptions or judgement.

Use your client's website.
Use your client’s website.
Looking at analytics data is an important step.
Looking at analytics data is an important step.

Look at Analytics Data

During my recent project the analytics data was a strong driving force, as it should be. Once we looked at the data it was obvious where we had to focus our efforts. It showed us that out of the 250,000-ish monthly visitors over 95% start out on a single post page and a relatively small percentage view a second page. We needed to focus on making the single page better since that’s where new users become familiar with the website.

This step allows you to view the website with an attitude closer to an average user’s. In our case we tried to figure out why our single page wasn’t working and what we could do to persuade visitors to view more pages.If your budget allows it is a good idea to get a testing group together. A couple of people who are within the target user group should do. Ideally you should be in one room with them, watching and recording how they browse. This will give you key insights into what works and what doesn’t.

Communicate With the Site Owner

Talk as much as possible to the owners/managers of the website, and not just about the project at hand. Talk to them about board games, vacations, sports, their favorite chocolates. You should get to know them, not just their project. This may allow you to better anticipate their needs, improve your relationship, and perhaps get future work.

It's important to communicate with your client.
It’s important to communicate with your client.

Of course you should also talk a lot about the project. What their goals and plans are, do they have any difficulty with the backend, do they spend too much time on trivial things? You could help them out there as well – a slicker admin translates to happier site manager, which translates to a better website, which trickles down to a better user experience for end-users as well.Real life can sometimes throw a wrench in the works. You may find the owners/managers uncooperative, unresponsive or just plain annoying. There is no one way to get past this. If you can resolve the issue great, if not, just make do with what you have. Planning and rebuilding is a multi-pronged approach. Communication is a strong pillar, but it’s only one of many.

By the end of this stage you should know what the website is all about, what the strong and weak points of the website are and why the rebuild is needed.

Define the Requirements

Once you agree to a project you’re bound to receive instructions on what you need to do. Unless you are receiving them from someone equally well-versed in coding, the instructions will only scratch the surface at best.

You’ll need to communicate with the project’s manager to clarify and expand on the requirements. Try and spot holes by thinking through all possibilities. For example:

“As shown in the designs, the featured image should be displayed in a box above the excerpt.”

As a coder you should ask questions like: What if there is no featured image? What if a featured image is set but the file can not be found? What if the image uploaded is smaller than the defined area? What if the uploaded image has a really weird aspect ratio, how should it be cropped?

Covering all the bases in advance is great because you don’t have to think while coding. You look at the specifications and write up the code needed to make them happen, no unknowns.

Starting With Data Requirements

I like to start with data requirements. It goes without saying that a WordPress-based project should support all built-in WordPress functions out of the box. Beyond that, you should be familiar with the inputs required for any given module.

For example, the project I led called for webinars. Webinars are live events, which users can sign up for and view live. The events are recorded and published as on-demand videos later. We decided that webinars would be a custom post type and I started mapping out the data needs to make our functionality happen, such as:

  • Webinar ID (from GoToMeeting)
  • Sponsors
  • Speakers
  • Wistia Video

My favorite way of working is to create these right away using Advanced Custom Fields. I use the pro version due to the advanced field types, but you can use the free one just as effectively.

Some webinar options created with ACF
Some webinar options created with ACF

Try not to get carried away with field types here. As you can see, the webinar ID field is a simple text field. In the final version this is actually a custom made field type, which connects to the GoToMeeting API. It pulls in all webinars and allows users to choose from a dropdown list.

The input is a select list, however the output at the end of the day is an ID string just the same. Due to this, using a text field for planning is perfect, no need to stray from the planning path to make the interface perfect at this point.

Another huge advantage of ACF is that it gives you prior knowledge of how your input and output will work. You know in advance that you’ll be creating the fields within ACF. Reading the documentation tells you how these fields can be hidden, exported, imported and so on. ACF offers standard functions for retrieving the values of these fields, looping through repeater fields and even creating options pages. This takes a lot of the development burden off your back.

Think in Terms of Processes

I strongly believe that a good rebuild should take the admin into account. Managing a website should be a task, not a chore; it should be a smooth part of someone’s day, not something they dread. As I mentioned before, a happy admin will translate to happier users.

I like to map out all the processes that take place on the site. One such example would be the publishing of posts. Where does content come from? Do authors enter it into the admin or do editors do all the work? If you can find problem-points you can easily make people’s lives’ easier.

Let me give you two examples.

Sticking with webinars, the old data requirements were much heavier. Admins needed to enter the starting time, the registration link and a bunch of other information. Copying data from one source to another manually gives rise to all sorts of problems. We’ve all messed up copy-pastes before and what if someone modifies the webinar in GoToWebinar? Will they always remember to update the post on the website?

We solved this by using the API to pull in as much data as possible. Aside from minimizing the required input fields we were able to grab registration fields as well making sure that registration for the webinars remained on-site. This should increase our registrant counts and provide a better user experience.

Another good example of process-based thinking is how we created the Easy Featured Images plugin, which I showed you how to make in another recent article. One of our efforts will be to create better images for our content; we’ll back-track a bit and find better images for our most popular posts. This would normally require the following procedure: Find the image, go to the post edit page, open the media screen, upload image, set as featured image. Having to load each post edit page adds a considerable time increase to the process.

So we created a plugin, which allows you to remove/change/add a featured image from the admin post list, no need to go into each post separately.

Using Easy Featured Image for a better user experience
Using Easy Featured Image for a better user experience

Do You Have Everything You Need?

At this stage you can pretty much figure out if your plan is doable based on the input data and the visuals and process descriptions provided. Ask questions like: will I be able to pull in all the data for a webinar using the GoToMeeting API if all I have is the webinar’s ID?

The answer is: Of course not, you’ll need API credentials as well. You should create an options field for those, or define them as constants in your wp-config.php file. Either way, the point is you now know what is needed, you can catch potential problems, and you can finalize your plan.

I can’t stress enough how important this planning stage is. I haven’t made any empirical observations but, it feels like every minute I spend planning, I save two minutes of coding time. Knowing the exact meta fields needed, the exact flow of the registration process, the detailed design of the pages to be built allows you to code without distractions. No need for guesswork, you don’t need to figure out what will work and what won’t, no need to go back and forth discussing while you’re working on them. Just look at a feature’s requirements, build it, pat yourself on the back and move on.

Create a Coding Plan

The coding plan is completely separate from the project plan. The client doesn’t even have to be aware of it, let alone the details. It should cover code formatting rules, file naming conventions, usage of object oriented language, where code is stored, how others can contribute, and so on.

A well-thought out coding plan will ensure that all code written for the project is consistent and, more importantly, code written afterward complies with the same rules. I’m not sure I can give you a comprehensive list of what a coding plan should/shouldn’t contain, it would probably take up another lengthy article in itself. Instead, I’ll show you what my last rebuild project’s plan contained.

1. High-Level Guidelines

High level guidelines govern the major, wide-reaching aspects of the project. Here are some examples of what we set out and stuck to:

  • All code must adhere to WordPress standards
  • All additional functionality must be provided by extendable, properly maintained and highly rated plugins from the repository
  • If the above criteria can not be met by a plugin or a plugin doesn’t exist we will create our own, release it into the repository and maintain it. In other words: there can not be any site-specific plugin activated.
  • Where appropriate object oriented code must be used. This includes plugins created. Procedural code should be used where it is most widely used, such as within theme files.
  • The code running on the production site can not be changed directly under any circumstances.
  • Code must be managed using a version control and ticketing system

These are the kinds of high level guidelines we set out in the very beginning. I think that relying on plugins like we have for projects is a great way to ensure a long lasting build. I would like to point out that we did make one exception to this rule: it can be discarded when it doesn’t make sense to release a plugin because the functionality is so specific to the website.

The only example of this is the advertising system which is highly tailored to the website. We did manage to boil it down to a custom widget and a custom template tag though. We too care to code this in a modular way, just like we would a plugin.

2. Coding Environment

The coding environment was created to be flexible and above all easy to duplicate. A little while ago I showed you how to create a test site with Vagrant and we used this same method here.

The benefit of using a virtual machine is that all that is needed to duplicate the server environment exactly are two files, totalling around 2.5Kb.

At the end of the day anyone can set up the same server in minutes using these two files.

Create a test site with Vagrant.
Create a test site with Vagrant.

We created a private repository on GitHub for the project and mandated this as the only way to manipulate the code. We also made our documentation a part of this repository; it’s not just the code that’s in there.

We made the use of Composer a requirement to pull in PHP packages we used and Bower a requirement for third party Javascript packages we used. Just like the guidelines for using plugins, this is meant to make the project more flexible and long-lived.

Developers can recreate the exact server structure with Vagrant and can pull in the exact third party code used by issuing a simple composer install command. Everyone is always on the same page, awesome!

For the development process we use Gulp heavily. Gulp is an automation tool, which combines and processes JS files, Sass files, optimizes images, reloads the browser, creates test servers – whatever we need. Gulp saves us literally hours every day which will be amplified further once other developers start working on the project.

3. Coding Guidelines

We had strict rules governing how code could be written and how it was structured. The most important requirement we had was hefty documentation. All documentable elements (functions, classes, files, properties, etc. ) had to be documented using the phpDoc syntax. We defined the requirements right down to mandated properties of the documentation:

  • Short element name
  • Element description. Must contain usage examples where appropriate
  • Parameters
  • Return value
  • @since property (which version the element was introduced in)
  • @author property
  • @uses property for all functions used within the element that we created
  • Links to relevant websites

Here’s a short example of what a docblock would look like for one of our functions.

I also decided to set strict guidelines commenting Sass files. Commenting styles is not too common which is a shame because I think stylesheets can be way more ambiguous than PHP code. Among others, I set that each Sass file must have a file level documentation section which sets what the file contains and lists each section. Inline documentation must be provided if a rule is not crystal clear.

Maintaining this list is a bit of a hassle for sure. It does increase the time you spend coding but it pays of in spades in the long run. You (and anyone else) will know where to find things, it’s nice and readable, coder friendly and well organized.

The guidelines also cover how code should be structured on a file-level, the style guide to follow (100% WordPress) and other minutia which you can tailor to your own liking.

4. Complete the Coding Tasks

This is a pretty short step in terms of description, but will take the most time. The only advice I can give you is to not waver from the plans and guidelines. This doesn’t mean that everything is set in stone. If you come across a situation which truly warrants a change in your plans, it’s ok to go ahead with it.

However, whim and spontaneity should be taken out of the equation at this point. Following your guides will ensure modular, predictable code which is the goal.

Clean up and Migrate the Database

With a site that’s been around and heavily used for 5+ years, the database can be a bit of a jumble. So, I made a three-step plan for managing the database migration:

  • Download the actual database to a local server
  • Weed out all unnecessary data
  • Test the new database on a remote test server

I used phpMyAdmin for the whole process. It’s relatively easy to install on a Vagrant box. If you don’t already have it you can use sudo apt-get install phpmyadmin. I chose to use Apache2 for the server and not to configure the database with dbconfig-common.

The next step is to add Include /etc/phpmyadmin/apache.conf to the /etc/apache2/apache2.conf file. Finally, restart the server using sudo service apache2 restart.

At the end of the process you should be able to reach phpMyAdmin by going to http://yourserver.local/phpmyadmin.

I looked through all the database tables to figure out what wasn’t needed. We had two main places of bloat: the meta tables and the users table (lots of phoney registrations). The usermeta table was especially bad since 10-20 rows of metadata were being generated for each user, including the phoney ones. Some of this data was never used, it was legacy code from years back.

Before we begin, I want to mention that in the examples below the table prefix is the usual “wp_”. We use a completely custom prefix (something to the effect of JIBuh34483wfIh84r_) but I renamed all tables to be able to work faster in phpMyadmin. After the database pruning I reverted the table names.

Please note that all queries below will lead to the deletion of users. Use them at your own risk!

Removing Phony Users

The first thing I did was remove user accounts that were spam or otherwise suspicious. Initially I just removed any accounts with empty data where data was supposed to be: emails, user_logins and passwords:

Another issue I found is that some users did not have capabilities assigned to them. Whether this happened because of fake signups or because we had an error somewhere in our registration script is unclear, but the end result is that these users couldn’t log in properly anyway. We decided to get rid of all these users. We kept our original database at hand so if anyone complains we can restore their account. The following SQL query will remove all users who do not have capabilities set in the usermeta table.

From here on out it’s educated guesswork. Browsing around, I found that one indication of a suspicious user was a lot of dot characters in the email, like: [email protected]. I didn’t just want to delete all users with X or more dots because some were legitimate users. We have a lot of emails from institutions, so [email protected] might well be a perfectly valid email. So I just selected all users with these email addresses and went through the list manually.

Next, I got a list of temporary email address providers and deleted all users who used them. I found a great list in a gist (that sounds like a Dr. Seuss quote!), which I formatted to look like this:

The final step was to look for other patterns, which would allow me to delete users en-masse. I used two separate strategies. First, I found some keywords found within emails that pointed to fake accounts. Some examples were: buy, weight, guide, fashion, cheats, finance, cialis, viagra. Upon selecting all emails with these words I realized that all of them were fake so I could run a simple delete command.

The second strategy was to find signups from the same domain. We were bound to get some from universities and companies we are affiliated with, but a sure sign of spam is more than one signup from for example. I used a lot of PHP for this one because this was the fastest way I could think of.

I temporarily added a domain column to the users table. I wrote a but of code that cycled through all users and extracted the email’s domain and placed it in the new column. I then listed all users, grouping them by the email domain and displaying the count. This allowed me to figure out which email address domains were spam.

Our results.

As you can see from the results, there are a few suspicious ones in there. As a microbiology website, I doubt that 14 signups from “” are real. I weeded out the domains that seemed fake and deleted all emails associated with them.

Slimming Down the Usermeta Table

The usermeta table can get out of hand, especially if you have a lot of fake accounts like we did. Once we removed all fake rows from the users table we could remove all usermeta rows associated with those accounts with a simple query:

If I remember correctly, this alone deleted about 150,000 rows of data! The next step requires a bit of manual labor. I looked at all the different usermeta keys to figure out which ones were needed and which ones weren’t. To list then, I used the DISTINCT keyword:

This resulted in a list of around 300 meta keys in use. I narrowed these down by finding the ones we would use in the rebuild of the website and the ones used by WordPress by default.

As far as I know the ones WordPress uses are:

  • first_name
  • last_name
  • nickname
  • description
  • rich_editing
  • comment_shortcuts
  • admin_color
  • jabber
  • aim
  • yim
  • default_password_nag
  • use_ssl
  • show_admin_bar_front
  • show_welcome_panel
  • dismissed_wp_pointers
  • nav_menu_recently_edited
  • managenav-menuscolumnshidden
  • closedpostboxes_{post, dashboard, page, …}
  • metaboxhidden_{post, dashboard, page, …}
  • meta-box-order_{post, dashboard, page, …}
  • screen_layout_{post, dashboard, page, …}

I made a list of custom meta keys we use, such as “facebook”, “position”, “twitter” and so on. I deleted all rows from the meta table which did not contains the ones we plan on using.

Other Meta Tables and Options

The meta tables for comments and posts and the options table can be slimmed down in a similar fashion. Find out what keys WordPress uses, add the ones you plan on using and delete everything else.

For the options table I decided we’d clear out everything and start from scratch. This is not a good idea for many websites. If you have data saved by plugins you will want to keep a lot of additional options.

To get the list of options WordPress uses by default I actually created a new WordPress install and listed the option keys from there.

Terms and Taxonomies

For the sake of completeness I wanted to go through these tables as well, even though they didn’t represent a lot of bloat. First, I listed all the taxonomies in use.

This returned two we didn’t need so I set out deleting them. I first deleted all the terms within the taxonomy. I then removed all related object relationships and finally, the taxonomies themselves.

Database Migration

The last step was to replace the test server’s database with this one. If everything worked well then the pruning was a success. If you see any missing data or something doesn’t quite add up, you made a mistake somewhere along the way.

Since modifying the database directly is dangerous if you don’t know what you’re doing (even if you do), I recommend keeping a backup (of course) and keeping a diary of all the queries you’ve made to change things.

Chances are a couple of queries caused all your problems, out of the 50 and you don’t want to go back and rewrite everything right? A simple text file with a query log will help you find the problem points quickly.

Testing and Finalization

Testing is an integral part of every coding process and can be one of the most grueling. Over the years I’ve noticed that you should get at least three people (groups of people) to test your work. There should be one coder testing (who was not involved in the main programming phase), one target user and one administrator/owner.

I’ve found that these three groups have very different goals and expectations and they are all adept at finding issues in their own field.

  • Coders know the bottlenecks of production, where it is easy to get lazy and all the other little details you hope no-one will find out. If uploading an image is necessary after you register they’ll simply close the browser window and log back in to see if your avatar serves up a nice little error. In other words, they will specifically test for errors which is great.
  • Admins of the website won’t find minute coding issues but they may find huge glaring errors coders miss. As a coder you sometimes can’t see the woods for the trees. You may be so engrossed in finding an error in the avatar system you don’t even notice that the default avatar used is not the one originally commissioned by the owners. Instead of making sure the website is error free, admins will make sure it conforms to requirements.
  • The target audience will make sure the site fulfils their needs. A site may have perfect code, it may conform to all the stated requirements, yet still fail. You may see users getting frustrated due to the long registration form, not finding a specific link or functionality and so on. These are good indicators of things that need to be changed.

Finally, you should make sure the website holds its own in the live environment. There are bound to be a few bugs that remain. This is a good time to test those parts of your coding plan that pertain to modifying the live website.

On our end we followed a strict deployment policy. Any bugs must be reported on GitHub. It must then be fixed and tested locally. It must be committed to the repository and the bug must be labeled “Fixed.” The theme must then be updated (this is done automatically) on the live site and must be tested there as well, ideally by someone other than the original fixer. Once the bug is fixed the issue is labeled as “Approved.”


A rebuild is a large project, but it doesn’t have to be difficult. As long as you plan the steps with care and make sure to communicate well with the client all it should require is time (as opposed to time, anger, frustration, backtracking, etc.).

The rebuild I worked on was completed in about five months. The site isn’t huge – we could have done it within two months if we got a move on. The extra time was used to take the pressure off development, make sure we had ample planning room and time to think each step through.

This did indeed add three months to the time frame, but we’re hoping that it increases the shelf-life of the website by years. Modularity was a key aspect so even if the site needs to be rebuilt at a later date a lot of the code can be reused, not to mention that there is almost no theme-specific coding in there. Almost all functionality is provided via properly maintained, high quality plugins.

Image credit: Pic Jumbo, Gratisography, Unsplash.

If you have any experience with extensive rebuilds I'd love to hear from you in the comments below.

Daniel Pataki

Daniel Pataki Hello, I'm Daniel and I make things for the web. I'm the CTO at Kinsta and I write for a number of amazing publications like WPMU DEV and Smashing Magazine. In my spare time you'll find me playing board games or planning the next amazing office game like the not-at-all-destructive Megaball.