For months I've been trying to plan out a good project structure for using git version control for WordPress website development that doesn't sacrifice the ability to update core and plugins through the WP dashboard, doesn't require an unconventional directory structure (wp-content outside of the WP parent folder) and that is easy to manage and deploy whole websites. I've read about submodules, subtrees, nested repos, etc, and I'm still having a hard time fitting it all together and choosing the right strategy.

Here's what I'm thinking right now, with my thoughts for how I would handle git repos in parenthesis.

root (main project repo)
|-- wordpress (public git repo added as subtree)
|    |-- wp-content 
|    |    |-- plugins
|    |    |    |-- my-custom-plugin (git repo added as subtree)
|    |    |    |-- other-plugin-with-git-repo  (git repo added as subtree)
|    |    |    +-- other-plugin-without-git-repo (ignored/untracked)
|    |    |-- themes
|    |    |    |-- my-custom-theme (git repo added as subtree)
|    |    |    |-- other-theme-with-git-repo  (git repo added as subtree)
|    |    |    +-- other-theme-without-git-repo (ignored/untracked)
|    |    +-- uploads (ignored/untracked)
|    |-- wp-admin
|    +-- wp-includes
|-- wp-config.php (ignored/untracked)
+-- other-files.txt

This leaves me with several problems/questions;

  • Automatic updates; I love the new auto updates feature, it could potentially save a lot of time and effort in keeping my sites updated and secure, but it seems that it throws a wrench in tracking code changes with git. Is there any way to track my code changes while still allowing WordPress core to auto update?

  • Does having subtrees under the WordPress core repo prevent me from using git to merge in new core updates or pushing out my changes back to the WordPress core repo (if I ever decide I'd like to be a core contributor)?

  • For plugins that don't have a public git repo, completely ignoring them creates the problem of not being able to quickly clone the entire site on a new server without manually copying files over to the server. It also causes a problem if I want to make changes to that plugin's code those changes aren't tracked and could easily be lost in a plugin upgrade.

So, to summarize, what is a good git+WordPress setup that avoids these problems? I would appreciate your feedback on my proposed project structure. Any way that you can help me improve this, would be much appreciated!

PS, if there is a better forum for this discussion, please point me there.

5 Answers 5


From my perspective there are two issues with your plan - Git and "conventional" structure. So basically everything. :)

  1. Git (and version control in general) is a poor tool for whole site stacks. Been there, done that, it hurt a lot.

  2. What you call an "unconventional" structure with content separated from core has been a very conventional and robust choice for any serious site for a while.

  3. There are pretty much no turn-key ways to combine whole site stack with native updates. It just doesn't go well together since it tries to achieve different goals in projects of different levels (developer in control vs end user in control).

If you ask me the best bet for whole site WordPress stack is currently Composer, however opinions may wary. :)

On your specific concerns:

  1. As above - native updates (more so auto) don't play well with tightly controlled stacks.

  2. WordPress core isn't developed in Git and doesn't accept pull requests, all contributions are (so far) via patch files to Subversion.

  3. You'll likely have to commit such plugins into your repo. Or go with another approach like Composer.

  • 1
    WordPress doesn't use Git for development, but there's a mirror at github.com/WordPress/WordPress (synced from the SVN every 15 minutes). It's not meant for pushing patches etc -- for that you definitely need to use SVN & Trac. I don't know if this will be suitable for the OP's purposes or not, but for completeness' sake, it exists.
    – Pat J
    Dec 31, 2013 at 20:56
  • @PatJ good point, I kinda assumed Q meant making use of that one, but maybe not
    – Rarst
    Dec 31, 2013 at 21:00
  • Very good points. I've got one whole site stack set up using git with submodules and it's a big pain in the ass. I guess I'm wondering if there is a less tightly controlled way to still take advantage of Git, but to also take advantage of the native updates to save myself some legwork. I'm a one man team at the moment, so I'm basically just trying to set up sites as efficiently as possible. Jan 1, 2014 at 13:10
  • @JosiahSprague if your main pain point is initial setup (rather than long term stack maintenance) it might make sense to focus on that with custom install.php routine or something and use normal update mechanics from there. Composer stack can handle updates very well in abstract, but it relies on quality of the packages you use and things like proxying official WP repositories for it isn't quite mature yet.
    – Rarst
    Jan 1, 2014 at 13:16

You might take a look at this issue and this issue.

Also take a look at the README files in each repo as well:

Based on above repos, as another example of a Git/WP setup, I created this. I opted to use symlinks for themes (I try to cover that in my README).

I'm kinda in same boat with the auto updates though ... My plan was to manually update WP submodule when updates happen. I think the alternative is, in theory (I have yet to test myself), to let the submodule update itself for minor updates (there's a WP setting for this) and then do a git force/reset of the submodule when major updates come out (maybe one of the answers here could be of some help ... of course, I think, one would want to target a specific WP tag when updating to next major release).

One thing to note is that if WP sees .git in the path(s), it will automatically turn off auto updates. For more info, see:

In order for Automatic Updates to be enabled, there are a few simple requirements:

  • If the install uses FTP for updates (and prompts for credentials), automatic updates are disabled
  • If the install is running as a SVN or GIT checkout, automatic updates are disabled
  • If the constants DISALLOW_FILE_MODS or AUTOMATIC_UPDATER_DISABLED are defined, automatic updates are disabled
  • If the constant WP_AUTO_UPDATE_CORE is defined as false, automatic updates are disabled
  • Your WordPress install also needs to be able to contact WordPress.org over HTTPS connections, so your PHP install also needs OpenSSL installed and working
  • Wp-Cron needs to be operational, if for some reason cron fails to work for your install, Automatic Updates will also be unavailable

Other related links:

May, 2015 update

I created this repo which is a quick way for me to start WordPress projects. My latest approach is to only version control the theme(s). In other words, I install WP locally (using setup in aforementioned repo) and on production, then I modify the config file on each system and git pull my theme(s) to get a functional site.


This type of development falls into the "not so easy and requires a custom workflow that might take a long time to be happy with".

I find Subtrees, submodules or nested repos, a huge pain in the ass.

Some thoughts (track everything).

  1. Enable auto updates with git/svn using:
    add_filter( 'auto_upgrade_ignore_checkout_status', '__return_true' );

Safe method via manual commits + email:

You can use a staging server and email update notifications to yourself, commit the updates and push to the live server which has auto updates off.

This also allows you to copy/paste folders for your own repos at will, which is often how I do it. It also makes it easy to clone/destroy multiple staging servers, git really comes into effect with this method since it is distributed.

The downside: copy/pasting folders, management.

Auto method

Set up a build script (Phing, Ant, Bash, Capistrano,etc) and some custom code that will do a git add + commit when a update is applied and send it to the live server. You can also separate plugins/theme repos and then have the script compile/move/whatever them, and/or use Composer in the mix.

Automating a workflow like this also tends to be inflexible and only worth it if you see a real need for the time invested.

The downside: inflexible, takes time to create.

Git should not be used for backups, and generally speaking there is no need for you to clone WP's commit history.


Ok, watching Mark Jaquith's talk here, maybe I'm on the wrong track. Here's another stab at it that tracks everything.

   root (main project repo)
    |-- wordpress (repo as subtree)
    |-- wp-config.php (ignored/untracked)
    |-- wp-content 
    |    |-- plugins
    |    |    |-- my-custom-plugin (repo as subtree)
    |    |    |-- other-plugin-with-git-repo (repo as subtree)
    |    |    +-- plugin-without-git-repo
    |    |-- themes
    |    |    |-- my-custom-theme (repo as subtree)
    |    |    |-- other-theme-with-git-repo (repo as subtree)
    |    |    +-- theme-without-git-repo
    |    +-- uploads (ignored/untracked)
    +-- other-files.txt

I guess the main downside with this is having a custom content directory, which has caused problems for me in the past with poorly written plugins and themes not being able to find the content directory.


After some more thought, since I definitely want to take advantage of native WP updates to save myself legwork, it doesn't make sense to track anything that WP will update using git. Here's a revised idea.

root (main project repo)
|-- wordpress (ignored/untracked)
|    |-- wp-content 
|    |    |-- plugins
|    |    |    |-- my-custom-plugin (git repo not connected to parent)
|    |    |    |-- other-plugin (ignored/untracked)
|    |    |    +-- modified-plugin (unignored, added to main project repo)
|    |    |-- themes
|    |    |    |-- my-custom-theme (git repo not connected to parent)
|    |    |    |-- other-theme (ignored/untracked)
|    |    |    +-- modified-theme (unignored, added to main project repo)
|    |    +-- uploads (ignored/untracked)
|    |-- wp-admin
|    +-- wp-includes
|-- wp-config.php (ignored/untracked)
+-- other-files.txt

Of course, then I lose the ability to track which plugins and themes are a part of the project from within the VCS, but I really only need that for backup purposes, and I'll be using some sort of regular backup system anyway.

So, the only thing this really lacks that I want is the ability to easily deploy the whole stack to different servers without using FTP to manually copy the whole thing over. Anyone have any thoughts on that?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.