WordPress Skeleton

At my “Scaling, Servers, and Deploys — Oh My!” talk (slides) at WordCamp San Francisco 2011, I talked a bit about my ideal WordPress repo setup. In the spirit of sharing, I’ve now made that skeleton setup into a GitHub repo.

What you get is a WordPress repo starter kit. WordPress is in a subdirectory (/wp/), content is in a custom directory (/content/), and uploads are mapped to /shared/content/uploads/, which is a Git-ignored location. Re-symlink as appropriate, or alter your deploy script to do the symlinking on the fly.

You get a nice clean wp-config.php with a few of my tips and tricks already implemented (like local-config.php support for local development). .htaccess is ready to go with WordPress rewrite rules for anyone running on Apache.

I don’t really expect people to use it exactly the way I have it set up (though feel free!). What’s more likely is that people will fork it, and then make it their own. For instance, you may want to add mu-plugins drop-ins that you frequently use. Have fun!

53 thoughts on “WordPress Skeleton

  1. Just found the repo, even before seeing this post – forked and downloaded. This is something I’ve been thinking on for a while; I already version my themes, but wondered if it would make sense to keep the whole shebang – WordPress core, themes, plugins – in one place to minimize the deploy process. Love the local-config.php idea, managing different setups can be a right pain at times.

  2. I’ve seen you describe this on various posts or comments previously and this is very useful.

    You could think about providing a local-config-example.php file which is meant to demonstrate what someone might put in that file. This is the way the Rails framework does it.

    In my similar setup, I have a wp-config.php file that includes in a credentials file which is symlinked similarly to the uploads directory that you mentioned.

    Having come to WordPress development from Rails, I’ve been wondering if the WordPress community had a similar Capistrano deployment approach. However, very few talk much about it. Would you say that most people default to Cowboy Coding?

    I have visions of writing some additional scripting support which enables me to spin up a site, a few essential plugins (with preferred settings), and even some default page/post content. Having this kind of automation would save me a ton of time and assure a higher quality baseline site.

    Anyway, thanks for putting this inspiration out there for the rest of us.

  3. Reblogged this on Jeremy Herve and commented:

    We’re all looking for new ways to make our jobs faster, and be able to deploy a basic WordPress install as quickly as possible.

    Well, Mark Jaquith just did the work for you. 🙂

    You only have to fork, add your own starter theme and favorite plugins, and you’re good to go!

  4. I noticed you have /sql-dump-*.sql and /db-sync in your .gitignore file. Could you explain your process for migrating the database from local to a development server? This has been my biggest problem with this workflow.
    I have currently been using a plugin like WP-Migrate-DB, then importing it via PHPMyAdmin on each push where content has changed. I feel like this could be automated but I’m not sure how.

    1. I just have a script that SSH’s in, does a mysql dump, rsyncs the file over, and imports it locally. I’ll share that at some point.

  5. I had to add the following to wp-config.php to get wp-admin working somewhat normally:
    define(‘WP_SITEURL’, ‘http://’ . $_SERVER[‘SERVER_NAME’] . ‘/wp’);
    define(‘WP_HOME’, ‘http://’ . $_SERVER[‘SERVER_NAME’]);

    Even then my example.com site’s wp-admin url became:

    1. That is expected. You don’t need to make these defines, you just need to set the home and siteurl options correctly in Options → General.

    2. I should have checked everything first. It seems that with these defines, the templates will try to pull from example.com/wp/content instead of example.com/content.

      Without adding those defines, visitors are redirected from example.com to example.com/wp

      is there an easy way to let everything work as if wordpress was not in a subdirectory?

  6. Very interesting Mark, thanks for posting! Could you also share your capistrano tasks with us? Do you use railsless-deploy and the capistrano multistage extension? I’m also very interested to see what you actually do with the WP_STAGE and STAGING_DOMAIN constants? What is your process when you have to migrate a WordPress site from one domain to another (e.g. staging to production)?

    1. This will all be revealed soon! There’s a “sister project” I’m working on that will do all of that, and reveal the purpose for WP_STAGE and STAGING_DOMAIN.

  7. Thanks for sharing. Will likely use this for WordPress repos moving forward. I am especially interested in the environment configurations. I gave a talk on this at WordCamp Chicago 2011 – http://bit.ly/NbnlFP. Excited to see someone so close to WordPress Core doing the same.

  8. As a self-affirmed cowboy coder with very little Git experience, is there anyone out there that can point me to a step-by-step resource to actually using this in a day-to-day project? I just grasp how this actually .. uh.. works?

  9. Hi Mark. First off, thanks for this, it looks like an ideal setup. Unfortunately I am not being able to make it work correctly, not even locally.

    What I did was this
    1) I created the ‘wp-skeleton-test’ database locally
    2) Under ‘localhost/wp-skeleton-test’ I used a standard wordpress package to populate the database
    3) I then emptied the local ‘wp-skeleton-test’ directory and I added your wordpress skeleton
    4) I created local-config.php and added the database details

    Browsing the website works perfectly (index.php includes wp-blog-header.php and everything works from there on), but trying to login ad admin always redirects back to the home page.

    I’m not even confident that the 3 steps process I used was the right one. If it was then I have no idea why this setup won’t let me login.

    Appreciate any insight you may have.


  10. This is great stuff, I was trying to find a decent git/deploy setup myself last week, and I’m glad I found this setup, it looks great.

    One other thing I’m trying to achieve, is to run multiple sites on a single directory containing WordPress, instead of having a seperate wp directory for each site. I got this working by using a symlink where you have the wp directory in your setup, pointing to the wp folder elsewhere on my server. This resulted in WordPress thinking it wasn’t installed, since it couldn’t find the “level up” wp-config.php (require_once uses the absolute path). However, this seems to be fixed easily by creating a wp-config.php in the wp directory with just this line of code:

    Also, working with symlinks, WP updates can be done absolutely instantaneously; all you have to do is change the symlink. You can even centralize this by using this setup:

    /home/foo/www/ (web root)
    /home/foo/www/wp (symlink to /home/resources/wordpress/wp)

    /home/resources/wordpress/wp (symlink to 3.4.1)

    In this scenario, upgrading wp for all your websites would be as easy as to pull the new tag for a new release, and change the /home/resources/wordpress/wp symlink.

    Anyways, still experimenting with this, I’d be interested to hear your thoughts. And thanks again for sharing your skeleton setup.

    1. How do I “pull the new tag for a new release”? I tried this:

      git checkout origin/3.4-branch

      but that gives me 3.4.3-alpha. I’m interested in the most recent stable build. Can I use Git to clone a specific tag, or am I better off just downloading it manually, like this for example:

      wget http://wordpress.org/latest.tar.gz

  11. Hi Mark,

    I’m really keen to start using WP Skeleton, but I’m having some set up issues.

    I’ve zipped and installed WordPress Skeleton into a local folder ‘/vcip.com’. I have set it up as a local Git repo. I then created a database and user and added the info to local-config.php. I also generated and added the salts.

    When I go to the site locally, it redirects to http://kdev.vcip.com/wp-admin/install.php and I get “This webpage has a redirect loop”.

    This is the first time I’m setting up WP in a non-standard way. Any help is much appreciated!


    (P.S. If I can get this up and running, I’m going to run a WP Skeleton and WP-Stack talk at WordPress London.)

    1. just wanted to let you know an actual noob benefited from this post of yours. Thanks for sharing, was my first time trying this too.

  12. “uploads are mapped to /shared/content/uploads/, which is a Git-ignored location”

    Why don’t you submit your images to version control? Does git not play well with binaries?
    Perhaps I’m missing something, but adding your ‘uploads’ folder in the repo seems like a handy way of keeping your local/production sites in sync. How else would you upload images to the live server?

    1. Git does not play well with binaries. And putting uploads into version control would be really confusing (and kind of pointless, because there is image data in the database which isn’t in version control).

    2. ok, got it, hadn’t thought about it like that until now. Thanks Mark. What do you think is the best way of keeping your uploads in sync? I develop my sites locally in MAMP so I could just use the sync feature in Transmit.

  13. Hey Mark, great stuff! I use your wp skeleton all of the time.

    Do you know of anyway to add a custom default WP themes directory repoas a sub-submodule into the WP submodule that you have here? (I delete the default wp-content/themes directory and clone my own themes repo instead).

    The end goal is to create a single repo that includes your WP Skeleton, the WP SVN submodule, my usual mu-plugins submodule, and my usual themes submodule. Ideally, each of these things would be easily updatable with a simple git recursive update (or clone).


  14. I just discovered this via another blog post of yours, and wanted to maybe sync up sometime. Since local development never seems to match production (and WordPress by design has no concept of mixed environments), I created something similar:

    > https://github.com/ericclemmons/wordpress-skeleton

    The value prop is creating a Vagrant VM with a working WordPress install that can be deployed & synced easily, so you always work on local, test on stage, and push to prod, rather than editing themes & plugins on prod (as most people seem to do).

    This this is *extremely* daunting and forcing architecture into something that, by design, doesn’t really seem ready for it, I’m moved off the project onto other ones… I would still like to talk or maybe leverage your services in regards to a git-driven WordPress workflow!

  15. Hmm it seems like your blog ate my first comment (it was super long)
    so I guess I’ll just sum it up what I wrote and say, I’m thoroughly enjoying your blog.
    I too am an aspiring blog blogger but I’m still new to the whole thing. Do you have any helpful hints for beginner blog writers? I’d definitely appreciate

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s