Author: erik

  • Grunt Automation for WordPress developers

    Grunt Automation for WordPress developers

    This is the third article in a series of developing for WordPress in a DevOps friendly way. The previous articles:

    1. Introduction to WordPress and DevOps
    2. Developing with WordPress and Vagrant
    3. Grunt Automation for WordPress developers
    4. WordPress configuration management

    In the previous two posts we’ve had a look at the various tools we need to create an automated workflow for developing and a little bit about how Vagrant can be used to create a better development environment. We’ve also briefly touched on using Grunt and wp-cli to automate setting up WordPress inside the environment. In this post we’ll dive deeper into how to use Grunt to automate even more of the WordPress setup.

    There’s a Git repository available with code for this post here: https://github.com/eriktorsner/gruntautomationforwp I suggest you clone or download the code to your development computer to make it easier to follow along.

    What’s our goal?

    In short. We want to run a single command at the command line to install WordPress, all our wanted plugins and other vital pieces of configuration. The end goal is to automate it to the extent that it can be part of a fully automated, non-interactive, deployment process.

    Looking back at the first post in this series I talked a bit about DevOps and how it’s a bit of a challenge to make WordPress a good fit for it. Automation is one of the cornerstones within DevOps and historically WordPress has been more focused on getting up and running quick than on supporting an automated workflow.

    Well, that changed entirely when wp-cli came onto the scene a few years back. Wp-cli stands for WordPress command line interface and is a project that aims to enable automation of WordPress management. Wp-cli makes it possible to automate installation, setup, theme and plugin installations and a lot of other common WordPress management tasks like modify settings or even add pages and posts.

    The other part of the automation work will be carried out by Grunt. Grunt is a “modern JavaScript task runner” and allows us to create tasks that can be executed from the command line. So we can create a task “wp-install” that uses wp-cli to install WordPress and run that task from the command line using a simple “grunt wp-install”. The most common use case for Grunt is to run things like css and javascript minification or compile SASS file to css. But we’ll use Grunt mainly as a task runner for DevOps related tasks. That doesn’t stop you from using Grunt for those other things as well which may be a very good idea for your project.

    Creating the environment

    In the previous post, we covered how to get started with Vagrant. To follow along in this post I’m assuming that you’ve read that post and have installed the prerequisites for running Vagrant on your development computer. I’ve made a separate Github repository available for this post, so from now on when I’m talking about specific files, I’m referring to the ones you can find in the git repo at https://github.com/eriktorsner/gruntautomationforwp. If you have any problems following these steps, be sure to read up on the previous post and post any questions in the comments below if you’re still having issues.

    A quick checklist to get you started with this Vagrant box

    1. Edit Vagrantfile (hostname, dns names and ip-numner) to fit in your environment
    2. copy localsettings.json.template to localsettings.json
    3. Run “vagrant up” to initialize the new machine”
    4. Go to folder /vagrant inside the virtual machine and run “npm install”

    Wp-cli + Grunt

    To show what Wp-cli can do in terms of automation, we’ll use it to perform the following tasks:

    1. Install WordPress
    2. Install and activate a few plugins from the official WordPress repo
    3. Change a few settings

    As we’ll be doing this by automating wp-cli via Grunt. Let’s have a look at the important parts of the Grunt file that comes with this post (see the top of the post for information on how to get it). The first thing to notice is on 32 where we define the function getLocalSettings, a simple helper function.

    [code firstline=”53″ title=”getLocalsettings” language=”js”]

    function getLocalsettings(test) {
    ls = grunt.file.readJSON(‘localsettings.json’);
    if(ls.wppath === undefined) ls.wppath = shell.pwd() + ‘/www/wordpress-default’;
    return ls;
    }

    [/code]

    We’ll use this function in each of our Grunt tasks that deals with wp-cli so that we can get the parameters we define in localsettings.json into action. Let’s look at the settings file to get a hunch of what kind of parameters we’re including

    [code title=”localsettings.json” language=”js”]

    {
    "environment": "development",
    "url": "www.gruntautomationforwp.local",
    "dbhost": "localhost",
    "dbname": "wordpress",
    "dbuser": "wordpress",
    "dbpass": "wordpress",
    "wpuser": "admin",
    "wppass": "admin",
    "wppath": "/vagrant/www/wordpress-default"
    }

    [/code]

     

    The idea is to have anything that is specific for this specific machine should be a parameter in this file. And the point of having settings in a json format is that json can be easily accessed both from javascript code like in the Gruntfile and in PHP code as well.

    Let’s look at the first task defined, the default task:

    [code title=”Grunt default task” language=”js”]

    grunt.registerTask(‘default’, ‘Log some stuff.’, function() {
    ls = getLocalsettings();
    grunt.log.write(‘localsettings successfully read URL=’ + ls.url).ok();
    });

    [/code]

    It will simply read the settings file and output the URL parameter from it, so it’s a simple test. Let’s try it within the Vagrant machine:

    [code language=”shell”]
    $ cd /vagrant
    $ grunt
    Running "default" task
    localsettings successfully read URL=www.gruntautomationforwp.localOK

    Done, without errors.
    [/code]

    The next task to look at is the wp-install task, it’s a bit more interesting:

    [code title=”Gruntfile wp-install” firstline=”14″ language=”js”]
    /*
    * Installing WP
    */
    grunt.registerTask(‘wp-install’, ”, function() {
    ls = getLocalsettings();
    wpcmd = ‘wp –path=’ + ls.wppath + ‘ –allow-root ‘;

    shell.mkdir(‘-p’, ls.wppath);

    if(!shell.test(‘-e’, ls.wppath + ‘/wp-config.php’)) {
    shell.exec(wpcmd + ‘core download –force’);
    shell.exec(wpcmd + ‘core config –dbname=’ + ls.dbname + ‘ — dbuser=’ + ls.dbuser + ‘ –dbpass=’ + ls.dbpass + ‘ –quiet’);
    shell.exec(wpcmd + ‘core install –url=’ + ls.url + ‘ –title="WordPress App" –admin_name=’ + ls.wpuser + ‘ –admin_email="[email protected]" –admin_password="’ + ls.wppass + ‘"’);
    } else {
    grunt.log.write(‘WordPress is already installed’).ok();
    }
    });
    [/code]

    • Line 18 is just loading the localsettings as we saw above
    • Line 19 creates the base string for the wp-cli command. Note that we’re adding the switch –allow-root since this task is likely to be executed by root in a different environment like production. We’re also adding the –path switch which will instruct wp-cli to install WordPress in a sub folder.
    • In line 23 we’re checking if WordPress is already installed or not.
    • Lines 24 to 26 are executing the wp-cli commands “core download”, “core config” and “core install”.

    There are a few interesting things to note. The first is obviously that after running this task we’re going to have a fully functioning WordPress installation in a sub folder. All parameters we needed are kept in a separate file which is fundamentally good for our efforts to make this a fully automated WordPress install. We’ve also managed to install WordPress in a sub folder that is explicitly kept out of source code control.

    The reason for that is that WordPress in not our code, it’s a depencency to us. We want to avoid adding dependencies in our source code tree (look inside .gitignore, we’re explicitly ignoring the www sub folder) for several reasons. But the most important reason is not size or bloat, it’s the ability to handle upgrades well. WordPress and it’s extensions are upgraded frequently with major and minor upgrades. If you add all the source code for WordPress, themes and plugins into your own source code tree, you will be stuck with the task of upgrading them once new versions arrive, and they do quite often.

    A clean separation between your own code and the dependencies means that you can easily test your code with the newest versions of each dependency. If your code breaks as a result of upgrading one of the third party plugins, the clean separation and automated setup makes it super easy to test and fix any such problems before you upgrade anything in production. That’s a big deal.

    So, back to our example, let’s run the wp-install task:

    [code language=”shell”]
    $ grunt wp-install
    Running "wp-install" task
    Downloading WordPress 4.3.1 (en_US)…
    Success: WordPress downloaded.
    sh: 1: /usr/sbin/sendmail: not found
    Success: WordPress installed successfully.
    [/code]

    Adding more dependencies

    Obviously, we’re going to need more dependencies. Let’s add a few plugins from the WordPress plugin repository. This is done with the wp-cli command “plugin install”. Let’s look at the next task in Gruntfile.js:

    [code title=”Gruntfile wp-install” firstline=”32″ language=”js”]
    /*
    * Setting up WP
    *
    */
    grunt.registerTask(‘wp-setup’, ”, function() {
    ls = getLocalsettings();
    wpcmd = ‘wp –path=’ + ls.wppath + ‘ –allow-root ‘;

    // some standard plugins
    stdplugins = [‘if-menu’, ‘baw-login-logout-menu’,’google-analyticator’];
    for(i=0;i<stdplugins.length;i++) {
    name = stdplugins[i];
    shell.exec(wpcmd + ‘plugin install –activate ‘ + name);
    }
    })
    [/code]

    • Lines 37-38 are similar to the wp-install task
    • Line 41 sets up an array of plugins we want to install
    • Lines 42-45 iterates that array and creates a wp-cli command that installs and activates all the plugins in the array.

    So no more manual plugin installations in the WordPress admin area! Let’s run the Grunt wp-setup task:

    [code language=”shell”]
    $ grunt wp-setup
    Running "wp-setup" task
    Installing If Menu (0.3)
    Downloading install package from https://downloads.wordpress.org/plugin/if-menu.zip…
    Unpacking the package…
    Installing the plugin…
    Plugin installed successfully.
    Success: Translations updates are not needed for the ‘English (US)’ locale.
    Activating ‘if-menu’…
    Success: Plugin ‘if-menu’ activated.
    Installing Login Logout Menu (1.3.3)
    Downloading install package from https://downloads.wordpress.org/plugin/baw-login-logout-menu.zip…
    Unpacking the package…
    Installing the plugin…
    Plugin installed successfully.
    Success: Translations updates are not needed for the ‘English (US)’ locale.
    Activating ‘baw-login-logout-menu’…
    Success: Plugin ‘baw-login-logout-menu’ activated.
    Installing Google Analyticator (6.4.9.6)
    Downloading install package from https://downloads.wordpress.org/plugin/google-analyticator.6.4.9.6.zip…
    Unpacking the package…
    Installing the plugin…
    Plugin installed successfully.
    Success: Translations updates are not needed for the ‘English (US)’ locale.
    Activating ‘google-analyticator’…
    Success: Plugin ‘google-analyticator’ activated.

    Done, without errors.

    [/code]

    Working with settings

    The last part I’m going to cover in this post is a little bit on how to manipulate WordPress settings. Wp-cli is not the only option we have to get settings from a text file (code) into a live WordPress installation, but since wp-cli can do this, let’s have a look at how.

    Most settings in WordPress are stored in a table named wp_options (assuming you’ve kept the standard “wp_” table name prefix). In order to change any of those settings via wp-cli, we first need to figure out what the various settings are called. Wp-cli have a sub command “option” that lets us list, add, delete or modify settings. For instance, if we want to change the settings “Site title” and “Tagline” we could use wp-cli to list all options and search for the options we want to find. In the wp-install task, we set the string “WordPress App” as the title, lets search for it:

    [code language=”shell”]
    $ cd /vagrant/www/wordpress-default/
    $ wp option list | grep ‘WordPress App’
    blogname WordPress App
    [/code]

    Ok, there’s only one single row in the options table with that string, so we can safely assume that the option called “blogname” corresponds to Site title. Let’s look for the tagline, we haven’t changed it yet in our test installation, so it should still read “Just another WordPress site”:

    [code language=”shell”]
    $ wp option list | grep ‘ust another WordPress site’
    blogdescription Just another WordPress site
    [/code]

    Right. The parameter tagline that we can control in the WordPress admin is found in the option named “blogdescription”.

    Knowing what the options are called makes it possible to set them via wp-cli. We can add a few lines to the wp-setup task:

    [code language=”shell”]
    shell.exec(wpcmd + ‘option update blogname "Another title"’);
    shell.exec(wpcmd + ‘option update blogdescription "experimental tagline");
    [/code]

    Running the wp-setup task again, we should now see:

    [code language=”shell”]
    $ grunt wp-setup
    Running "wp-setup" task
    Warning: if-menu: Plugin already installed.
    Activating ‘if-menu’…
    Warning: Plugin ‘if-menu’ is already active.
    Warning: baw-login-logout-menu: Plugin already installed.
    Activating ‘baw-login-logout-menu’…
    Warning: Plugin ‘baw-login-logout-menu’ is already active.
    Warning: google-analyticator: Plugin already installed.
    Activating ‘google-analyticator’…
    Warning: Plugin ‘google-analyticator’ is already active.
    Success: Updated ‘blogname’ option.
    Success: Updated ‘blogdescription’ option.

    Done, without errors.
    [/code]

    Note that wp-cli won’t attempt to reinstall the plugins that are already activated but instead just sends a warning saying that it’s already there. The last few lines tells us that the blogname and blogdescription settings are now updated to their new values. Mission accomplished.

     

    Summary

    In this post, we’ve taken another few steps towards gettings WordPress under our control. We’ve discussed the reasons why we want to treat WordPress itself as well as any third party extensions as dependencies rather than a part of our own application. Not in the sense that the code we develop would work well without WordPress and the plugins, but because we need to keep them out of our code base for upgrading and testing reasons.

    In future installments in this series, we’ll dive into dealing with content and try to find ways to make WordPress separate content and content. If that sounds weird or if you’re just the curious anyway, stay tuned for the next episode. In the mean time, share insights, questions or other feedback in the comments below.

    WordPress DevOps – The book

    I’ve written an ebook on this subject. Released in September this year on Leanpub.com. Expect a 100+ tightly written pages where we walk through the creation of the skeleton of a WordPress based Saas application, connected to Stripe and Paypal with a working deployment process that takes content into account. Just add your billion dollar idea. Jump on over to Leanpub to get your copy.

    WordPress DevOps - Strategies for developing and deploying with WordPress
    WordPress DevOps – Strategies for developing and deploying with WordPress

     

     

     

     

     

     

     

    [wysija_form id=”3″]

  • Developing with WordPress and Vagrant

    Developing with WordPress and Vagrant

    This is the second post in a series of developing for WordPress in a DevOps friendly way. The other articles:

    1. Introduction to WordPress and DevOps
    2. Developing with WordPress and Vagrant
    3. Grunt Automation for WordPress developers
    4. WordPress configuration management

    Lets recap a bit to last post in this series. Vagrant is a piece of software that will help you automate the creation of Virtual Machines right on your development computer. The benefits of running your WordPress project inside a Vagrant machine are that (1) you can use the same software stack of operating system, web server and database as you will use in production and (2) you can make changes to the development environment without affecting the rest of your computer or any other projects. Lastly (3) it’s super easy to make sure that all developers working on the same project actually has the exact same environment.

    In this post we will get a bit practical and demonstrate how Vagrant works. We will set up a WordPress installation inside a Vagrant machine and then surf to it from your development computer and we will automate as much of the WordPress installation as possible. In fact, it’s so automated out of the box that you will only need to type five (5) commands to get your WordPress install up and running. We’ll also touch briefly on the tools Grunt and wp-cli, but more in depth articles on those tools will follow soon.

    Preparing

    Before we can do anything else, we need to get Vagrant and a Virtual Machine manager installed on our development computer. This step depends on the OS on your machine and as the Vagrant documentation says, it’s extremely easy. Head over to their downloads page and install it using standard procedures on your OS.

    The same goes for the Virtual Machine Manager. Vagrant supports VirtualBox and VM-Ware as well as a few other possible backends. I’m a long big fan of VirtualBox so that’s what I recommend. Head on over to the VirtualBox downloads page and get the version that’s right for your computer. Install it using standard procedures on your OS.

    We also want to install a plugin to Vagrant called host-updater. This plugin will automatically rewrite the hosts file (/etc/hosts) on the host machine, that makes it so much easier to surf to the WordPress installation later on and keep. At the command prompt of your computer type:

    [code]
    $ vagrant plugin install vagrant-hostsupdater
    [/code]

    Setting up a remote repository

    Clone or copy my Get repository for this blog post, https://github.com/eriktorsner/wordpressvagrant, into a folder on your computer. From now on, we’lll refer to that folder as the project folder. I suggest your start your own remote Git repository (on github or elsewhere) so that you get your project under source code control right from the start. It’s good development practice.

    The included files.

    As you can see, there are only a handful of files in the code you’ve just copied. Let’s talk about what they do:

    1. Vagrantfile This file is the main Vagrant configuration file. It defines the virtual machine that we’ll soon fire up. If instructs Vagrant to create a machine with a specific hostname, a specific amount or RAM and disk, what IP-number to use and a few other things. At the top of this file, there are 4 lines of code that needs to be changed to suit your environment, but other than that, you should be able to use this file as is. One of the most important parameters that is defined in this file is “config.vm.box” that tells Vagrant what base image to start with. We’re using “ubunty/trusty64” which gives us a bare bones Ubuntu 64 bit operating system to start with.
    2. Subfolder vagrant. This subfolder contains some additional settings for Vagrant that is uses during the provisioning phase. We’ll talk more about provisioning further down, but basically it’s a script that is executed the first time we start the virtual machine and that installs “everything else” which in our case means the nginx webserver, MySQL database server, PHP and a bunch of other useful tools.
    3. package.json is the settings file for the Node Package Manager (NPM). We use NPM to install Grunt and some of it’s dependencies.
    4. Gruntfile.js is the settings file for the Grunt automation tool. We’ll talk more about Grunt in a later episode, right now it’s enough to know that Grunt can be used to automate things and that we’ll use it to automate WordPress installations.
    5. .gitignore is simply a file that tells Git what files and folders we want to keep out of version control
    6. localsettings.json.template In our approach to WordPress we want to automate as much as possible and to do that, we need a place to store things that are unique to this particular environment. Since this file should never be added to Git, I’ve included a template, not the actual file. Any setting that will differ from this development environment we’re currently creating and the live production environment should be captures in this file. In this template file, we have things like URL, path to WordPress, WordPress passwords etc. The parameters in the template happen to nicely align to most default values defined in Vagrantfile and provisioning.

    Starting the virtual machine

    Before we can start the Vagrant machine for the first time. Open Vagrant file and make sure lines 3-6 have sensible values. Hostname, devdns and testdns should have values that makes sense for your project name and ipnumber should be a unique ip number that is not already used by another virtual machine on your computer.

    [code language=”ruby”]
    # -*- mode: ruby -*-
    # vi: set ft=ruby :
    hostname = ‘wpvagrant’
    ipnumber = ‘192.168.50.33’
    devdns = ‘www.wpvagrant.local’
    testdns = ‘test.wpvagrant.local’
    [/code]

    Once you’ve made those changes, fire up your Vagrant box with this simple command:

    [code]
    $ vagrant up
    [/code]

    Now is a good time to grab a cup of coffee. Vagrant will download and install a lot of things. On my computer this process normally takes 5-8 minutes, but it will vary depending on network speed and your computers performance.

    Working inside the virtual machine

    Once Vagrant has finished it’s setup process we’ll log into the command line shell of the virtual machine. Type the command vagrant ssh and you should be greeted with something like this:

    [code]
    $ vagrant ssh
    Welcome to Ubuntu 14.04.2 LTS (GNU/Linux 3.13.0-46-generic x86_64)

    * Documentation: https://help.ubuntu.com/

    System information disabled due to load higher than 1.0

    Get cloud support with Ubuntu Advantage Cloud Guest:
    http://www.ubuntu.com/business/services/cloud

    0 packages can be updated.
    0 updates are security updates.

    vagrant@wpvagrant:~$
    [/code]

    An important feature of Vagrant is that it keeps folders on your development computer in sync with a special folder inside the virtual machine. By default, this folder is named vagrant and is located at the root of the file system. Go to that folder and check out the contents, it should match exactly what you see in the project folder on your development computer

    [code]
    vagrant@wpvagrant:~$ cd /vagrant
    vagrant@wpvagrant:/vagrant$ ls -alg
    total 52
    drwxrwxr-x 1 vagrant 4096 Sep 18 10:07 .
    drwxr-xr-x 24 root 4096 Sep 18 10:05 ..
    drwxrwxr-x 1 vagrant 4096 Sep 17 18:12 .git
    -rw-rw-r– 1 vagrant 216 Sep 18 09:46 .gitignore
    drwxrwxr-x 1 vagrant 4096 Sep 18 10:01 .vagrant
    -rw-rw-r– 1 vagrant 1461 Sep 18 10:07 Gruntfile.js
    -rw-rw-r– 1 vagrant 1079 Sep 17 18:12 LICENSE
    -rw-rw-r– 1 vagrant 19 Sep 17 18:12 README.md
    -rw-rw-r– 1 vagrant 3995 Sep 18 09:40 Vagrantfile
    -rw-rw-r– 1 vagrant 405 Sep 18 09:11 localsettings.json.template
    -rw-rw-r– 1 vagrant 354 Sep 17 18:52 package.json
    drwxrwxr-x 1 vagrant 4096 Feb 4 2015 vagrant
    drwxrwxr-x 1 vagrant 4096 Sep 18 10:08 www
    [/code]

     

    Installing WordPress

    We are only a few commands away from installing WordPress. First we’ll copy / renamelocalsettings.json.template so that we have a correctly named localsettings file.

    [code]
    $ cp localsettings.json.template localsettings.json
    [/code]

    As I wrote above, no actual changes are needed inside this file as long. Next, we’ll use npm to get all the dependencies for Grunt.

    [code]
    $ npm install
    [/code]

    Npm takes a few seconds and when it’s finished you should see that you have a new sub folder node_modules in your project folder. And lastly, we’ll use Grunt to install WordPress using a custom Grunt task:

    [code]
    $ grunt wp-install
    [/code]

    And that’s it. WordPress should be ready to use. Test it by using a web browser on your desktop and type in the address to your development machine. The default is: http://www.wpvagrant.local (but you’ve might have changed it in the Vagrantfile).

    Summary

    In this article, we’ve looked at how easy Vagrant can be made part of your development environment, as a side effect you’ve also saw a glimpse of how WordPress installs can be automated using wp-cli and Grunt (more on that in a later post). Since Vagrant has grown in popularity there are many alternative Vagrant default configurations you can use for WordPress development. The one I’ve share is this article is geared towards developing web sites with WordPress, but there are others that are organized to be more suitable for Theme or Plugin development. To mention a few:

    • Varying Vagrant Vagrants (https://github.com/Varying-Vagrant-Vagrants/VVV) is the first I encountered that is focused on WordPress. My configuration is based on this.
    • VCCW (http://vccw.cc/) is another good option. One of the benefits is that it uses Chef for provisioning rather than a shell script as mine and VVV does.
    • dominikzogg/vagrant-php (https://github.com/dominikzogg/vagrant-php) is a generic PHP development environment that supports WordPress among other things. I find this very interesting because it makes it easy to try your application on different versions of PHP, including PHP 7 and HHVM

    In the next post in this series, we’ll dive deeper into automating the WordPress installation even further. We’ll look at how to get plugins, themes and settings in place using code rather than manual configuration in the WordPress admin area.

    Until then, over to You, let me know what you think in the comments.

    WordPress DevOps – The book

    I’ve written an ebook on this subject. Released in September this year on Leanpub.com. Expect a 100+ tightly written pages where we walk through the creation of the skeleton of a WordPress based Saas application, connected to Stripe and Paypal with a working deployment process that takes content into account. Just add your billion dollar idea. Jump on over to Leanpub to get your copy.

    WordPress DevOps - Strategies for developing and deploying with WordPress
    WordPress DevOps – Strategies for developing and deploying with WordPress

     

     

     

     

     

     

     

    [wysija_form id=”3″]

  • Introduction to WordPress and DevOps

    Introduction to WordPress and DevOps

    This is the first article in a series of developing for WordPress in a DevOps friendly way. The other articles:

    1. Introduction to WordPress and DevOps
    2. Developing with WordPress and Vagrant
    3. Grunt Automation for WordPress developers
    4. WordPress configuration management

    In this post, we’ll talk about what DevOps means to WordPress developers.  Can DevOps deal with WordPress and perhaps more important, can the WordPress community deal with DevOps?

    So what is DevOps? Wikipedia describes DevOps as a development method that emphasizes collaboration, integration and automation between software development teams and other IT professionals. To understand what that means in practical terms it’s easier to look back at how IT used to work at many companies. There’d be two teams of technical people, one team would focus on developing web stuff or internal applications. The other team would focus on maintaining servers, network infrastructure, look after backups among other things, commonly referred to as operasions. The communication between them was often kept at a “need to know basis” and blame storming would be common. Not everywhere, but often enough for problems to arise.

    The introduction of DevOps as a concept was first and foremost a mindset change. With better collaboration between development and operations came better understanding of how each part of the equation works. Better understanding also quickly led to better internal processes and soon thereafter, better tools and more automation. Today the term DevOps often means a mix of these things. DevOps can mean the process or method of getting internally developed software into production. DevOps can sometimes refer to a set of tools to help that work. Or in some places DevOps is simply the new name for the part of IT department that deals with these issues.

    In the the context of WordPress, we need to think of DevOps primarily as automation. A large part of the work we do in WordPress is within the system. Write blog posts and publish them is the perfect example of that. As long as the WordPress installation is backed up on a regular basis, that’s fine. But software developers also work on the system. Expanding WordPress with new plugins, installing eCommerce addons, developing a custom theme etc. At some point, those changes needs to be pushed from a developers environment to the production environment, also known as deployment.

     

    If we do that manually using ftp to move files and the WordPress admin area to install plugins by hand, we’re pretty far from an automated workflow, we’d call it manual deployment. But if we can lift ourselves so that deploying a new version of a WordPress site into production is fully automated, well, then we’re working in the spirit of DevOps.

     

    But it’s not enough just to automate and be done. A good deployment process will only deploy code that passes some quality tests. It will allow for some sort of rollback if we discover problems. And it is designed so that we never ever lose data as a result of a deploy. The relevant question is how do we get from a manual deployment workflow to a fully automated safe workflow with quality assurance?

    I find that when someone's taking time to do something right in the present, they're a perfectionist with no ability to prioritize, whereas when someone took time to do something right in the past, they're a master artisan of great foresight.
    The general problem

    Automation requires upfront work

    Let’s just get this out of the way first. There is no silver bullet.

    But having said that, there are development tools available that will help you along the way but setting them up correctly will cost you some time at the beginning. Once you’ve spent that time and get it all into place, you’ll gain it back quickly.

    Next, we’ll briefly cover the tools that I prefer to work with to create this automated workflow. There are plenty of good tools available, I’d be very happy to hear what tools you have found to solve the same, or other, challenges.

     

    The tools

    Git for Source code control

    Git has quickly become the source control and versioning system of choice for many people. The WordPress development team still relies on Subversion but they are also making all of WordPress core as well as all plugins in the official repository available at Github as well.

    Unit testing

    To maintain code quality we need to use testing and since WordPress is a PHP project, the natural unit testing tool is PHPUnit by Sebastian Bergmann. There are plenty of good tutorials that will help you get started with PHPUnit and WordPress, one of my favorite guides is written by Pippin Williamson.

    Vagrant as development eenvironment

    Vagrant is a piece of software that will help you automate the creation of Virtual Machines right on your development computer. There are many benefits of running your WordPress project inside a Vagrant machine, the most obvious ones are that (1) you can install more or less the same software that you will use in production same version of Apache or nginx, same php version, same mysql version etc. And (2) you can make changes to the development environment without affecting the rest of your computer or any other projects. And (3) it’s super easy to make sure that all developers working on the same project actually has the exact same environment. No more “this works on my machine” conversations.

    Grunt and wp-cli for automation

    Wp-cli is a command line tool for automating installation and configuration of WordPress. It can be used to install a brand new WordPress site as well as to add or remove plugins, update individual settings such as “blogname” etc. We can use it to make sure that our WordPress installs are setup exactly the same in all of our environments (development, staging and production). Using wp-cli can be made even better when we add Grunt. Grunt is a JavaScript based command line tool that makes it easier to automate common tasks, like running a couple of wp-cli commands for instance. Grunt and wp-cli makes it possible to automate pretty much everything when it comes to WordPress installations.

    WP-CFM

    WP-CFM stands for WordPress configuration management. It’s a tool that helps us store a selection of WordPress settings from the database to a file that we keep in git. WP-CFM was built with wp-cli in mind, so by combining them we get a method of managing WordPress settings in the source code control system so that they are easily moved between development, staging and production. There are a few caveats, but there are luckily some workarounds for those.

    Rocketeer for deployment

    There are a few open source deployment systems available. The Ruby system Capistrano might be the most well known right now. For PHP developers there is a system called Rocketeer that does much of the same things but where you can reuse some of your PHP classes (and skills).

    So, will WordPress and DevOps get along?

    There are some distinct challenges when it comes to automating WordPress web development. In the tools list above I’ve outlined the tools I think we need to create a fully automated deployment process that enables us to move our project from development to other environments.

    However, there are a few things that are not covered by any of these tools and it’s the primary reason that WordPress and DevOps sometimes can’t get along at all. It’s the content.

    WordPress makes no distinction between content and content. For instance, your particular menu structure is store as a combination of taxonomies and posts. That’s right. A menu item is a type of post. And the start page of your WordPress site is a post. But the blog posts that are written by the site editors are also posts (naturally), and any images that are uploaded on the live site are also posts.

    Our challenge is that when we deploy our WordPress site from development to production is that some content (menu and start page for example) are kind of part of the core web site you’ve created and you want the deployment process to transfer (and update) it on the live site. But other content is just content and if the deploy process overwrites normal posts we have a catastrophe on our hands.

    WordPress has a hard time seeing the difference and that’s going to be the primary challenge when we want WordPress and DevOps to play along nicely.

     

    Nitty gritty

    Every item in the tool list, how to use them and how they fit into our process is a large enough topic for a 2-4 blog posts each. I’m not covering them in detail in this post. But as it happens, this post is only the first in a series of blog posts on these topics.

    The next post will cover how to set up a good development environment using Vagrant and Git and after that we’ll look into automation with Grunt and wp-cli.

    So stay tuned to this blog.

    WordPress DevOps – The book

    I’ve written an ebook on this subject. Released in September this year on Leanpub.com. Expect a 100+ tightly written pages where we walk through the creation of the skeleton of a WordPress based Saas application, connected to Stripe and Paypal with a working deployment process that takes content into account. Just add your billion dollar idea. Jump on over to Leanpub to get your copy.

    WordPress DevOps - Strategies for developing and deploying with WordPress
    WordPress DevOps – Strategies for developing and deploying with WordPress

     

     

     

     

     

     

     

    [wysija_form id=”3″]

  • eBook on WordPress development and deployment

    Advanced WordPress development

    Last weeks I’ve been busy finishing up an eBook with the kind of straight forward title: WordPress DevOps – Strategies for developing and deploying with WordPress It’s a 100 page guide covering how You can get WordPress to work a little bit better in a proper development process, covering automation, testing and deployment.

    If you’re interested, click here or on the book cover above to head on over to Leanpub and sign up for it. You’ll get an email as soon as it’s available for download. And yes, it will be available in pdf, epub and mobi formats. When you do sign up, please share your email address with me, I’d love to be able to stay in touch with you.

  • Creating a persistent ssh tunnel in Ubuntu

    In situations when no VPN is either not available or you just think it’s an overkill to configure an ssh tunnel can be a pretty good alternative. An SSH tunnel works by setting up an ssh connetion between two hosts and use that connection to transport normal network traffic. On one side of the tunnel, the OpenSSH software takes anything that is sent to a specific port and sends it over to the other side of the connection. When the packets arrive on the target side, the OpenSSH software forwards them to the correct local port. Natrually the traffic is encrypted on it’s way, thereby creating a miniature VPN.

    Setting up an ssh tunnel is quite straigt forward, for example at the terminal:

    ssh -NL 8080:127.0.0.1:80 [email protected]

    Let’s break that down:

    • -N means that SSH should just create the connection and then do nothing.
    • -L means that the local side is the listening side. If you want it the other way around, use -R instead.
    • 8080:127.0.0.1:80 tells ssh that the listening side should listen on port 8080 of it’s localhost interface and the other side should forward it to port 80. So, on the machine that runs this command, anything sent to 127.0.0.1:8080 is forwarded to port 80 on the other side
    • [email protected] tells ssh to connect to 192.168.10.10 with username root

    There’s really only one problem with this. Whenever the ssh connection breaks the tunnel will break and you have to rerun that command again. Depending on your situation this might be a problem and that’s why autossh exists.

    Autossh

    Autossh is a tool that sets up a tunnel and then checks on it every 10 seconds. If the tunnel stopped working autossh will simply restart it again. So instead of running the command above you could run:

    autossh -NL 8080:127.0.0.1:80 [email protected]

    Note: starting an ssh tunnel with autossh assumes that you have set up public key authentication between the client and server since there’s no way for autossh to ask you for the password. Especially if you want to follow the rest of this article and have the tunnels start automatically. Please read more here  for details on how to setup public key authentication.

    Start automatically

    Having autossh monitor your tunnels is a great advantage, but it still requires a command to be run whenever autossh itself would die, such as after a reboot. If you want your ssh tunnels to persist over a reboot you would need to create a startup script. Since Ubuntu 9.10 (Karmic) Ubuntu have used Upstart as its main mechanism to handle startup scripts so the rest of this article will discuss how such a script can be created.

    I wanted to achieve three things with my startup script. First, I’d like my tunnel to come up when the computer boots. Second, I’d like to be able to keep configuration for multiple tunnels in one file. And lastly, I’d like to be able to control (start/stop) my tunnels without having to kill individual ssh processes.
    Three files are created:

    First, /etc/init/autossh.conf:

    description "autossh tunnel"
    author "Erik Torsner "
    
    start on (local-filesystems and net-device-up IFACE=eth1 and net-device-up IFACE=wlan1)
    stop on runlevel [016]
    
    pre-start script
    NUMHOSTS=$(egrep -v '^[[:space:]]*$' /etc/autossh.hosts | wc -l)
    for i in `seq 1 $NUMHOSTS`
    do
    start autossh_host N=$i
    done
    end script

    Second, /etc/init/autossh_host.conf

    stop on stopping autossh
    
    respawn
    
    instance $N
    export HOST=$N
    
    script
    ARGS=$(head -$N /etc/autossh.hosts | tail -1)
    exec autossh $ARGS
    end script

    And lastly, the config file /etc/autossh.hosts

    -NL 8080:127.0.0.1:80 [email protected]
    -NL 8080:127.0.0.1:80 [email protected]

    Rationale for each file

    /etc/init/autossh.conf
    This is the main startup script. The first parts of the file sets the conditions that triggers this script to start or stop. I’ve told my script to start as soon as the local filesystem is ready and when mu network interfaces are up. Chances are that you want to modify this to suit your computer, at least the name of the network interfaces.
    The actual script part is a simple bash script that checks the contents of a config file to determine how many tunnels that needs to be started. It then starts a numer of autossh_host jobs with an individual id that happens to correspond a the line number. It would have been nice to just start the autossh processes directly from this script, but autossh is a blocking command and only the first line would be executed on startup. Dropping the process to the background using a & character at the end would work but the resulting autossh processes would be out of our controll.

    /etc/init/autossh_host.conf
    This is the job where the interesting part actually happens. Note that this script doesn’t have any “start on” stanza at all, it’s only ever started when the main job tells it to start. The interesting part is its “stop on” stanza that simply says that it should stop whenever the parent job is stopped. Using this mechanism all child jobs can be controlled via the parent job.

    The script part uses a very naive method of picking out the correct line from /etc/autossh.hosts and use that line as the argument for autossh. Note that with this approach, the config file /etc/autossh.hosts can’t contain any empty lines or comments at all. Room for improvement.

    /etc/autossh.hosts
    This is just a config file with one row per ssh tunnel to create. Each line consists of the entire parameter line sent to autossh. Again, please note that the parsing of this file is very naive and won’t allow for any blank lines or comments at all.
    Starting the tunnels
    If everything is correctly set up, you should now be able to start your tunnels using:

    sudo start autossh

    and stopping them with

    sudo stop autossh

    If you have problems, check out the logfiles under /var/log/upstart. There should be one logfile for each script/instance, so expect to find autossh.log as well as many autossh_host-N.log.

    Questions? Did I miss something? Is my solution entierly wrong? Let me know in the comments.

  • A slow host is a bad host

    Just a quick post about a discovery I just made. When using the Load Time Profiler plugin to measure load time, it’s possible to compare two hosting environments by looking at the first part of the load process, before any plugins or theme files are loaded. The last point such point measured by the plugin is post_exec_register_theme_directory that is added to the profiling data just before plugins are about to get loaded.

    On a really fast host running Apache2 without any PHP enhancements but with plenty of RAM and fast SSD disks, this event is done 18.4 ms into the process. This host happens to be my laptop. But please do note, the load time is measured entirely on the server side, so there’s no advantage of being on the same physical computer.

    On a really (really) slow host, a business account on Swedish hosting company Binero, the same exact point is reached after 220 ms(!). I’ve reported this to their support, but they seem to think that it’s completely in order so it’s not a matter of a single misconfigured server. They really are that slow. As a reference, a similar hosting provider, Loopia, is about 25% quicker at 165 ms.

    220 versus 18.4, that’s more than a ten times the load time. Actually, when looking at the total load time, including plugins and the theme, the Binero hosted account will sometimes consume more than 10 seconds before the page is sent back to the browser. Yes, we’re looking at moving that site to another home in the near future and being able to profile the load time behaviour was exactly the kind of data point needed to make that decision. With that kind of performance, there’s simply no other quick fix available.

    Now, go test your hosting provider and please let me know what you find in the comments below. Download the plugin here.

     

  • WordPress profiler

    WordPress profiler

    memory_added

    This post is part two of a mini series where I (1) explain why keeping track of WordPress load timing is important and (2) discuss how WordPress load time profiling can be done using a newly created plugin. If you want to skip the chatter and go straight to the plugin, you can download it here.

    I’ve updated my load time profiling plugin a little bit over the weekend. There are now two new features:

    1. The output will show you memory consumption at each log point
    2. The plugin will trace time spent in each function called via an ‘add_action’ callback.

    Lets talk about both these two a bit and why they make sense

    Memory consumption

    There are a few reasons that you want your WordPress installation to have as low memory consumption as possible.

    First of all, there is a limit. Sometimes on some hosts, you will get an error that tells you that your PHP script tried to allocate more memory than is available and it will halt execution. This is not a specific WordPress error, but since WordPress is built on PHP, you’ll get it sometimes. When troubleshooting this type of error, it’s not always obvious what code that is causing the problem. Even if Plugin A uses a lot of memory and pushes memory consumption right to the limit, it will sometimes load just fine anyway. But a little later, when Plugin B is initializing, your total memory consumption may hit the limit and processing will halt. When that happens, finding the problematic piece of code can be very time consuming, not to mention frustrating.

    The other reason is that allocating memory pretty much always takes a lot of time, memory allocation is simply an expensive operation. Not that each call to emalloc in itself is all that expensive, but when a script gradually built up memory consumption there have usually been quite a few emalloc calls under the hood. So the mere act of consuming memory also costs a lot of CPU cycles.

    The last reason is a matter of scalability. A script that uses 256Mb of memory will occupy the server RAM with… well, 256Mb. If your webserver only have 1024Mb available it can only make room for four 256Mb scripts running at the exact same time. If the script on average takes 2 seconds to finish it means that the maximum requests/sec that your server can handle will be heavily reduced. So you want your WordPress requests to consume as little RAM memory as possible simply because it means that the server can fit more requests into memory at any given point of time.

    All the three above reasons makes it important to be able to track how your WordPress installation uses memory. I hope you find it useful.

    Hooked functions

    One of the features that makes WordPress such a wonderful product is the ability for a theme or plugin to hook into it. In practical terms it means that a plugin or theme can request to be notified via a callback whenever WordPress hits a certain point in it’s execution, in WordPress lingo, such a callback is referred to as an action. For instance, most plugins uses a hook for the Init event that fires early in the startup process and allows a plugin to perform certain initialization before the page starts to render. Plugins and themes can register that they want a callback for the Init event by simply calling the add_action function. More than one plugin can hook up to the same event and when this happens WordPress will just execute them one by one.

    A potential problem with callbacks is that all plugins are not written with performance and memory efficiency in mind. On the contrary, some plugins will spend ages doing expensive initialization tasks and consuming a lot of memory for no particular reason at all. For the end user this means that the requested page is delayed until some plugin is done doing unneeded work. One example is the very popular NexGen Gallery plugin that on initialization will load a lot of PHP files into memory and perform some quite expensive initialization work on every single request, regardless if the resulting web page will actually display a gallery.

    In the first version of my Load time profiler plugin you could track how long time WordPress took to complete a few of the actions, but it was not possible to see how long each individual callback would take. In this version, I’ve added code to track this so that for instance when the Init action is fired, you can see the time consumed by each individual callback (click image to enlarge)

    init_breakdown

    One tiny drawback

    The traditional way to do profiling would be to run the code in a specific profiling tool that needs to be installed on the same server as your code is running on. In the case of WordPress, the challenge is that many production installations are running in hosted environments where the web developers can’t just go and install debugging and profiling extensions at will. This plugin is really an attempt to overcome this limitation by actually modifying how WordPress is executed in a controlled way. Three core WordPress files are copied to the plugin directory and are modified to (1) collect data on timing and memory consumption and (2) alter the include paths a little to avoid the standard version of those files. Feel free to check the modified files, they are stored under /path/to/plugins/loadtimeprofiler/resources and have the suffix _custom.php

    The drawback of this should be fairly obvious, since the code is modified, it’s not the exact same as in production and therefore, the results will differ ever so slightly between what’s reported and reality. So as long as you keep this in mind and use the tool sensibly, I think you can draw some

    Download

    I swear I will start the process to get the plugin into the official repository at wordpress.org asap, in the meantime click here to download the current version of the plugin.

    I’m eager to hear back from your. I’ll answer technical questions or listen to your critique. Whatever feedback you think is appropriate. Use the comments below to let me know what you think.

     

  • WordPress load time analysis

    Load time profiler ‹ Walltool — WordPress

    UPDATE Dec 8th 2013: I’ve updated the plugin even more. Read about it in part 2.

    UPDATE Dec 3rd 2013: While testing the plugin on a few installations, I discovered a couple of bugs. If you downloaded the plugin on Dec 2nd 2013, you may want to try the improved version available below.

    I’ve been working a lot with WordPress lately and doing so I’ve sometimes needed to trouble shoot slow WordPress installations. Naturally, I’ve googled for things like “wordpress performance”, “wordpress is too slow” and similar phrases. Almost always, those searches will take me to a page listing the top-10 things you should do to speed up your WordPress website. Those lists of tips are usually quite good, you’ll typically learn that you should install a caching plugin, clean up your database and get rid of unneeded plugins etc. Mostly quite useful information…. but with some important exceptions.

    Installing a caching plugin such as W3 Total Cache will often solve most of your performance problems as long as you have mostly a “read only” website. However, if your website is inherently slow when used without any caching, your users will notice it and suffer from it whenever they do anything that can’t be cached as easily, like posting comments or doing custom searches. The most scary example  I’ve experienced was an e-commerce website that was screaming fast as long as you were just browsing products (good) but was terribly slow when adding things to the cart (bad), entering a coupon code (worse) or checking out (flat out terribly bad). In that case, it didn’t matter much that the front page got a 90/100 score on Google Speed since the users had a terrible experience just as they were about to place their orders. So sometimes, a WordPress site need performance beyond what you can get from a good caching plugin.

    Maybe it’s time for a little clarification. When people talk about performance it’s common that a few important concepts are mixed up. For the remainder of this post, when I say performance I mean the time needed to create the main HTML document that WordPress generates and that IS the page. Specifically, I don’t talk about the size of or number of other resources (images, css-files, js-files etc) that your page needs. Those are almost always static and the webserver will seldom require the PHP  scripting engine to serve them to your users, and if your webserver actually is too slow, static files can easily be moved to a CDN anyway.

    When a user requests a page from (or makes an Ajax call to) your Wordpres site and that request can’t be cached, the entire WordPress system needs to initialize in order to generate the response. For the sake of argument, let’s divide the response generation process into two phases:

    1. Internal WordPress init. In this phase. WordPress will load itself into the PHP process memory, it will set up the database connection and read various options from the database. It will initialize your theme, meaning it loads the theme’s function.php into memory and allow it to register the hooks it want. It will also load the main php-file from all your active plugins and they will also typically register some hooks.
    2. Theme processing When phase 1 is ready, your theme will be called into action. If it’s a standard post or page, Wordpres will typically load your single.php or page.php and let it execute it’s code. That code will call internal WP functions such as ‘wp_head()’ or get_bloginfo() to do it’s job and sometimes, calling an internal function will call back into your theme’s function.php, it all depends on the theme.

    During these two phases, you really don’t have a lot of information about what WordPress spends the most time with and that makes it terribly difficult to know what you can do to optimize it. I found this very frustrating so at one point, I started hacking a few of the files in WordPress core in to insert debug information about what it’s doing. Specifically, I was inserting profiling code into wp-settings.php like this:

    require( ABSPATH . WPINC . '/version.php' ); // <--- existing line
    $profiledata['post_require_version.php'] = microtime(TRUE); // <--- my line

    Then in my footer.php, I’d output the content of the $profiledata array into HTML to review it. Naturally, modifying core files like that gets messy quite fast. You can easily break the entire site by accident  and any changes will be overwritten on the next WordPress upgrade. So even if I believe that I was gathering useful information this way, I needed to do it cleaner. So, (since this is WordPress) I wrote a plugin, I now have a working plugin that will do the following using a bunch of Ajax calls from an admin-page:

    1. Copy wp-settings and wp-config into a separate plugin folder
    2. Rewrite wp-settings and wp-config so that they contain profiling code as shown above and some modified path information.
    3. Via a special bootstrap php file, load wordpress using the modified versions of wp-settings and wp-config and at the end, output the profile data using json
    4. Submit the data back to the server for storage, and render an HTML table with all the profiling data.

    This is what it looks like:

    Load time profiler ‹ Walltool — WordPress

    And the complete content of the analysis can be downloaded here (tab separated text)

    One interesting thing is that this is not limited to just displaying internal WordPress load time analysis, if you want to, you can add additional profiling statements into your own theme code and have them displayed in the same table. I’d even say it’s the preferred thing to do. One thing that I’ve seen so far is that in a lot of cases, the WordPress internal stuff takes roughly 40-55% of the total load time, so to get the full story of what happens during load time.

    I’ve just finished writing this plugin so it’s really quite rough at the moment. It’s not been tested with a lot of WordPress versions and the UI is not at all what I’d want it to be. I’m in the process of adding it to the WordPress repository, should you want to look at it before that, feel free to download it from here:

    Download Loadtimeprofiler

    Feedback, comments questions? Use the comments below.

     

     

  • Rackspace and load test automation

    Well, last workday of this week turned out nice.

    I’ve been working with LoadImpact.com for a few months, providing text material for their blog. Mostly hands on technical stuff about load testing, how their tool can be used, and fun things you can find out with a good Load Testing tool at hand.

    But this week, one of my posts actually got published on the Rackspace Devops blog. I don’t have the numbers, but I’m suspecting that Rackspace to have quite a decent amount of readers. So Hooray! Not that Rackspace called me personally and begged for it, rather that Rackspace and LoadImpact are working together in other areas, but still, more readers, heh? Anyway, the space available for this first post on their blog was limited, so I almost immediately followed up with some nitty gritty details and a working demo. And yes, there’s code in there.

    I other news. Ferrari finished 9 and 10 in Belgium Grand Prix qualification (that’s F1) and I’ve just decided to port an ongoing project from CodeIgniter to Laravel 4. Only things that bugs me about that is that Laravel 4 seem to have more runtime overhead than CI. Expect more on the conversion process in the next few weeks.

    Now, time to prepare saturday dinner and a get glass of the red stuff.

     

     

     

     

     

  • WordPress file permissions

    WordPress file permissions

     

    In order for WordPress to be able to install a plugin and plugins or themes automatically there are a number of conditions that have to be met. If all those conditions aren’t met, one-click installations or upgrades won’t happen, instead, whenever you try to upgrade, WordPress will show you the FTP credentials input form. If you’re anything like me, you hate it.

    I sometimes run into this problem. My first instinct is to check the obvious file permissions. Will the web server have write access to all the important places. As long as we’re only talking about plugins and themes, important places means the wp-content folder. When I’m certain that the web server have write access, I typically try again and successfully upgrade my plugin.

    Every once in a while, installing or upgrading still won’t work even if I’m 100% certain that WordPress should be able to write everywhere it needs to. I end up searching for a solution for about 10 minutes, give up and resort to manually uploading plugins via ssh and get on with my life. Today I decided to find out the root cause of this problem and solve it. Writing this blog post about it servers as much as a ‘note to self’ as assistance to anyone else that trouble shoots this without finding a solution.

    The rules

    So, the rules for WordPress to be able to install and upgrade plugins and themes:

    1. The web server needs to have write access to the wp-content folder. For example on a Debian based system (i.e Ubuntu), this will be user ‘www-data’, on RedHat/Fedora, it’s typically user ‘httpd’ (plese correct me here if I’m wrong). WordPress will test this by writing a temporary file to wp-content and then remove it. There are plenty of blog posts, howtos and forum posts about this. They usually points back to this article: http://codex.wordpress.org/Changing_File_Permissions
    2. The files in wp-admin needs to be owned by the web server user. WordPress will test this by using PHP function getmyuid() to check if the owner of the currently running PHP script is that same as the owner of the newly created temporary file. If it’s not the same, WordPress will select another method of installation or upgrade.

    Rule #2 is what typically gets me. Whenever I move an existing WordPress installation to a new home, I’m sometimes (obviously) not careful with setting file permissions and file ownership and end up in this situation. Rule #1 is extremely intuitive, checking for write permission is close to second nature. But Rule #2,  checking file ownership in wp-admin… well, I’d even say it’s slightly unintuitive. If anything is worth protecting it should be the admin area, and being more restrictive with file ownership and permissions under wp-admin would even kind of make sense.

    Anyway. Comments, questions or other feedback. Please post a comment below.

     

    [wysija_form id=”3″]