Category: Code

  • Super simple backups

    Super simple backups

    In this post I explain a little bit about how I’ve set things up so that I’m comfortable knowing that my files are backed up to an Amazon S3 bucket every night. Most of this post should work exactly the same on any Linux or BSD system, but I’ve personally only used it on Mac.

    With this approach my backups are

    • Offsite – so that any amount of fire, earthquakes, floods or avalanches can’t take my data away.
    • Safe – I trust that the Amazon engineers are magnitudes better att maintaining their data centerns than I could ever maintain some local hardware
    • Secure – Again, I trust the Amazon engineers to have magnitudes better security practices than I ever will. Bad actors will find it more difficult to steal data from Amazon than from me.
    • Versioned, so I can go back to any older version of a specific file at any time. This protects me from a lot of my own stupid mistakes as well as the odd case of a ransomware attack.

    And since you’re going to want to know. I spend well under $1 / month for the 20Gb of backup storage I’m currently using. However the first month the storage bill as about $10, partly for the initial transfer but mostly because of a good deal of experimentation. Still bonkers cheap.

    Half the work is dotfiles

    Before you go ahead and copy this solution you should be aware that this backup approach only deals with content such as documents, source code, images, temporary files on the Desktop etc. It does not deal with installed software or settings.

    Besides the Amazon S3 backup described in this post I’m also using a combination of dotfiles and Bitwarden to backup software, settings and secrets. I’ll probably write something about that part of my setup later. All you need to know at this point is that the following solution solely focus on good old files.

    Also worth knowing is that this backup script deals only with files and folders under your $HOME folder. I keep my computer pretty tidy and make sure everything worth backing up sits somewhere in my $HOME. If you run things differently and want to backup other folders as well, you’ll probably find it easy enough to modify the script below.

    Requirements

    Not a lot of requirements at all, here we go:

    • Brew – to install the aws command line utility
    • An existing Amazon AWS account
    • An IAM user set up with a valid access key and secret

    I highly recommend creating a new IAM user just for this project. Even though it’s not covered in this tutorial it makes it possible to add restrictive access controls later on. Nothing worse that discovering too late that a lot of applications are sharing the same credentials.

    Creating the bucket

    First we need a bucket. Go to the Amazon S3 console and click Create a bucket. Most of the settings are straight forward.

    Select a suitable name, for instance the name of your laptop. Select a region, you probably want to select the closest region available to minimize network latency.

    Then there are a few key settings that you want to get correct from the start:

    • Make sure ‘Block all public access’ is enabled so that your files aren’t available from the Internet.
    • Enable Bucket versioning

    Installing aws command line

    Next we install the AWS cli tool using Brew:

    $ brew install awscli

    That’s easy. Next we need to set up the command line tool so it’s able to access our bucket. AWS Cli allows you to setup several profiles with different defaults. I highly recommend setting up a separate profile for the purpose of backups, I call mine ‘backups’:

    $ aws configure --profile backups
    AWS Access Key ID [None]: YOUR_AWS_ID
    AWS Secret Access Key [None]: SECRET_KEY
    Default region name [None]: us-west-2
    Default output format [None]: json

    If you’re already using Aws Cli for other things you can go a bit more advanced and edit the config files directly, Amazon has some great documentation about this here.

    It’s a good idea to test the settings with a simple command. Using the ‘ls’ command you should see the bucket you created earlier and if you’ve been using AWS previously, probably a few more:

    $ aws s3 ls --profile=backups
    2021-03-31 09:24:57 erik-laptop
    2021-02-15 00:16:17 some-other-bucket

    The backup script

    With a bucket and a configured command line tool in place it’s time to have a look at the actual script. I’ve created a folder named ~/src/backup and stored the below script as below is stored in ‘~/src/backup/backup-aws.sh’:

    !/usr/bin/env bash
     BUCKET="erik-laptop"
     FOLDERS="src Desktop Downloads Documents"
     PROFILE="backup"
    
     for FOLDER in $FOLDERS; do
         aws s3 sync $HOME/$FOLDER s3://$BUCKET/$FOLDER \
         --profile=$PROFILE
         --no-follow-symlinks \
         --exclude="/node_modules" \
         --exclude="/.vagrant" \
         --exclude="/vendor" \
         --exclude=".vdi" \     
         --exclude=".DS_Store" \
         --exclude="/project1/www" \
         --exclude="/project2/www" \
         --include="/project3/src/plugin_name/vendor"
     done

    Super simple right?

    The first three lines are just setting some config values:

    • BUCKET – the target AWS S3 bucket
    • PROFILE – the profile we defined when setting up the cli tool
    • FOLDERS – Any folder name under your $HOME that you want to include in the backup

    Further down the script You’ll notice that there are a lot of lines starting with ‘–exlude’. Each of these lines has a file pattern of files or entire folder to exclude from the backup. This list should be adapted to your own needs, here’s my reasoning for a few of these:

    • node_modules – When I need to restore this folder will/should be recreated by npm, no need to keep them in my backup
    • vendor – Same as above, but these folders will be recreated by Composer
    • .vagrant – This is a temporary folder created when using Vagrant. All my vagrant machines can be created and provisioned from scratch, no need to keep this state
    • .vdi – Disk images from VirtualBox. Same as with the .vagrant state folder, these are recreated on demand when I need them

    I’m also using an explicit ‘–include’ when needed. In one of my projects we have a folder named ‘vendor’ that actually can’t be recreated (as easily). So I’ve chosen to make sure ‘/project3/src/plugin_name/vendor‘ is included in backups as well.

    Depending on the type of projects and software you are working on or with, the list of files and folder to include or exclude may differ a bit so you may need to adjust the list. Amazon has good documentation on how to write exclude and include patterns here.

    Running the script

    I suggest running this script manually at least once. Make sure you are in the folder where you saved the script and type:

    # make it executable
    $ chmod +x backup-aws.sh
    
    #run it
    ./backup-aws.sh

    The first time will take an awful lot of time. My initial backup was about 6Gb (before adding more folders) and took a good 45 minutes on a fast Internet connection. Your milage will vary.

    When the initial backup is done you can try running it again to verify it’s working as intended. The second time around should be a lot faster, normally about 4-5 minutes on my laptop.

    Adding a cron job

    Once we’re satisfied that the backup script does what it should, it’s time to add a cron job for it. To edit your current users crontab using the Nano editor just type:

    $ EDITOR=nano crontab -e

    Add the following line to have this script run at 3:01AM every day

    1 3 * * *       cd /Users/myusername/src/backup && ./backup-aws.sh > /dev/null 2>&1

    How does this work?

    The magic sauce in this setup is the ‘aws s3 sync’ command. It will recursively copy new and updated files from the source directory on your computer to the destination which is an S3 bucket. It will figure out which files that have been created, updated or deleted since the last time it ran and transfer all those changes to S3.

    I think it’s fair to compare ‘aws s3 sync’ with rsync, but specifically designed to work with S3 buckets.

    Since the bucket we configured for this is versioned, previous versions of an updated or deleted file will still remain on the bucket. So what ever ransomware attacks you are subjected to you will always be able to retrieve an earlier version of the file.

    What am I missing?

    The whole reason I wrote this post is for you to criticize it.

    I’m the first to admit that I’m not terribly experienced when it comes to working with backups, but perhaps you are? I find this approach to backing up personal stuff so easy that there’s bound be some flaw somewhere in this setup that I didn’t understand or consider.

    If you spot the problem, don’t hesitate to comment below.

  • Software I use – 2021

    Software I use – 2021

    I haven’t written anything in this space for quite some time now. Last time I did I had just upgraded to a new Dell laptop with factory installed Ubuntu 16.04 (told you it was a long time ago). Well, that one got stolen and I thought that it might be a good time to switch to a Mac as the daily driver. So I did.

    Desktop tools

    Web browser

    Secure, Fast & Private Web Browser with Adblocker | Brave Browser

    I recently switched from Chrome to using Brave Browser as my primary web browser. Just like Chrome it’s Chromium-based which means that almost everything works the same way that I’m used to. I may actually give both Safari and standard Chromium a test drive before I decide which one to stick with.

    Messaging and email

    Overall Email has become less important in the past 6 months as Ive moved away from traditional consulting almost completely. The communication tool I use the most these days is Slack. This choice is obviously dependant on what the rest of your team is using but I actually also use Slack for solo projects because of some of the nice integrations.

    All my email accounts are Gmail and I use the Spark email client to manage them. I actually like the Gmail web UI but as soon as you have more than one account it gets clunky. Spark also has a great iOS client which makes managing emails as easy on the mobile devices.

    Password management

    Another recent switch. I was using LastPass for password management for a long time but recently switched to BitWarden. Last year LastPass announced that they were discontinuing their MacOS native client which made me go look for alternatives. Then again this year they changed their licensing model a bit. So now I’m a very happy using Bitwarden premium.

    Writing

    Even though I haven’t updated this blog a lot lately I am writing quite a bit of documentation and I tend to use Markdown whenever possible and when I do I use Typora. I also use the Grammarly desktop app from time to time to get hints on how to improve my language.

    Terminal

    I’m sort of always in the terminal so I’m actually not putting this under the dev tools section. I’m using iTerm2 instead of the terminal app that comes built in with MacOS. It has lots of features that I hardly know how to use but I use their split panes feature exactly all of the time.

    I’m using Z shell that has been the standard shell for Mac a few years now (replacing bash). Like so many others I also use the Oh My Zsh framework to configure it. From their own presentation:

    Oh My Zsh will not make you a 10x developer…but you may feel like one!

    https://ohmyz.sh/

    Development tools

    So I work almost exclusively with WordPress these days, as an effect from that most of the tools I use are PHP and MySQL centric.

    Development IDE – PHPStorm

    I use PHPStorm as my main IDE. It’s 200 Euros for the first year but the licensing cost then gradually shrinks to 120 Euros a year from the third year and onwards. But I won’t try to sell you on PHPStorm in this post I’m just going to say I think it’s well worth the yearly license cost.

    I also still use Sublime Text 3 for random note keeping and shorter texts burps but I hardly ever use it for writing code any longer.

    Laravel Valet

    This switch is super recent, I have been using Valet less than a week.

    As a carry over from using Linux I was fully invested in using Vagrant backed by VirtualBox for everything related to development. This isn’t nearly as nice on Mac as it is on Linux because the differences in disk performance makes it a royal PITA a lot of the time. Last week I moved one (1) test site over to Valet and decided that this is my new default dev environment in a heart beat.

    Vagrant

    I was using Vagrant exclusively up until just a week ago but from now on I’m probably only going to use it when it’s really crucial that I can emulate the entire production environment and that environment is more than just the web app (other sub systems, cron jobs, multiple databases).

    Tinkerwell

    Its time to Tinkerwell 💫

    Tinkerwell is basically PsySH in a nice UI with sensible defaults. It works really well with both WordPress and Laravel out of the box. If you have ssh access to your production environment it’s so powerful that I instinctively feel like I’m doing something criminal. Try it!

    Postman

    I think Postman is more or less the goto client for working with REST API development and testing and hardly needs an introduction. I’ve used it for years and it just keeps on getting better.

    MySQL Workbench

    I hear a lot of developers using other mac specific tools but I’ve always been quite happy with the official MySQL client from Oracle. Makes it easy to create users, schemas, tables, run queries etc.

    Other stuff

    There’s also a long list of smaller tools that I make use of pretty much every day.

    Better Touch Tool is a utility for some keyboard shortcut customizations in Mac. The one specific thing I needed was a way to drag the current window into the next space without using the mouse. Easy peasy with BTT.

    I use Airfoil satellite to stream audio from my iPhone to my Mac via the AirPlay protocol. I use it mainly for podcasts and audiobooks so I when I come back to the computer from a walk I can just continue streaming to the speakers instead of my headphones. I honestly can’t understand why this is not part of the OS. There’s also an open source tool for this, shairport sync but I never got it to work after the Catalina upgrade.

    I use Apowersoft Screenshot for quick screenshots but since a few months back I’m not able to add annotations to the images. So whenever I need to add text, arrows and other stuff I use Skitch that lets me do that but with a slightly less intuitive workflow.

    Every now and then I need to prevent my computer from going to sleep and when I do, I use Owly.

  • WordPress management the right way

    WordPress management the right way

    I first wrote about Wp-bootstrap in a post a few weeks ago and now it’s time for an update.

    New version 0.2.2

    Version 0.2.2 that was released today is actually quite a release. In this version, Wp-bootstrap is now feature complete to the extent that everything I described in my book, WordPress DevOps is now possible to do using Wp-bootstrap. This means that a bunch of Grunt scripts that quite honestly grew to be fairly complex can be replaced with a well formed, easy to read json file instead. I can’t tell you how nice that feels.

    Quality ASSURANCE

    I’ve got a separate repository on Github with the test cases for Wp-bootstrap. For the 0.2.2 release I spent a lot of time making sure to get code coverage up to an acceptable level. The overall coverage is now at 83%, a number I’m quite happy with at the moment. The missing 17% are in a part of the package that I’m considering scrapping and it’s not presented in the documentation, so no one should stumble on the untested code by mistake.

    References

    The big thing in this release is reference management. When you import options into WordPress using Wp-bootstrap, you might sometimes include a value that is actually a reference to a post ID. The most obvious example is the WordPress option “page_on_front” that stores the page ID for the page that works as the front page of your site. If you are using Wp-bootstrap to import the front page itself, chances are that the ID of that front page will be different between your development and production installations. So if you import the “page_on_front” setting, the integer value in the database will almost certainly be wrong.

    Wp-bootstrap can overcome this problem by managing these references for you. Just tell Wp-bootstrap which settings that contains references to a page/post/term. If that item was included in the imported data, Wp-bootstrap will update the database accordingly. This is a very powerful feature and it works across both posts (pages, posts, attachments custom post types) and taxonomy terms (categories, tags etc).

    Intended use case

    There is an intended use case or workflow that I had in mind developing this package. A quick overview:

    On the development server (hint: use Vagrant):

    • Start a new project by requiring wp-bootstrap in composer.json
    • Run vendor/bin/wpboostrap wp-init-composer to get easier access to the wp-bootstrap commands
    • Create a localsettings.json and appsettings.json
    • Make sure you exclude localsettings.json from source code control
    • Initiate the development installation with commands composer wp-install and composer wp-setup
    • As settings are updated, use the WP-CFM interface in WordPress Admin to include the relevant settings into the application configuration
    • As plugins and themes are needed, add them to appsettings.json and rerun the wp-setup command to get them installed into your local environment
    • As posts and menus are added, include them in appsettings.json.
    • When it’s time to deploy to a staging or production environment, run composer wp-exportcommand to get all content serialized to disk. Add them to your Git repo

    On the staging or production server:

    • Create the local database
    • Check out the project from Git
    • Create up your localsettings.json file with the relevant passwords and paths.
    • Run composer update
    • Run vendor/bin/wpboostrap wp-init-composer to get easier access to the wp-bootstrap commands
    • Run composer wp-install, composer wp-setup and composer wp-import

    Once the target environment has been setup, new changes from the development environment can be pushed by checking out the new changes using Git and rerunning wp-setup and wp-import.

    Take it for a spin

    Now it’s over to you. If you’re interested in a more structured workflow around WordPress, give Wp-bootstrap a try and let me know what you think in the comments section. Or better, get in touch to let me know how you can contribute to Wp-bootstrap. I’m eager to hear from you.

  • Easy wp-cli automation with wp-bootstrap

    Easy wp-cli automation with wp-bootstrap

    I’ve created a PHP Composer package to provide an easier way to automate WordPress installations using wp-cli. If you are unfamiliar with wp-cli and composer. I suggest you read up on composer here, wp-cli here and the rationale of automation in my book or in my blog series on the subject.

    Another great resources for learning more about using WordPress, git and Composer together is to check out the roots.io post on the subject as well as their Bedrock project.

    What is wp-bootstrap

    Wp-bootstrap is a composer package that adds a bunch of commands to your environment that helps you set up WordPress and themes, plugins and settings in a consistent manner using configuration files rather than scripts or worse, point and click installations. Wp-bootstrap depends on two files that it expects to find in your project root folder:

    1. appsettings.json that contains settings, themes and plugins that your WordPress site needs to use. It also has a way to manage some of the content of your application. This file is meant to be a part of your application and managed in a source code control system.
    2. localsettings.json that contains settings that are specific to each environment. This includes database name, password, WordPress installation path and more. This file is meant to be unique to each environment that your site runs in (development, staging, production etc) and is not supposed to be managed by source code control.

    By combining these two files wp-bootstrap is able to setup a WordPress installation from scratch, let’s see how.

    INSTALLING wp-bootstrap

    [code]
    {
    "require": {
    "eriktorsner/wp-bootstrap": "0.2.*"
    }
    }
    [/code]

    [code]
    $ composer update
    $ vendor/bin/wpbootstrap wp-init-composer
    [/code]

    To include wp-bootstrap to your project, just add the above lines to your composer.json file. Or if you prefer, use this command:

    [code]
    $ composer require eriktorsner/wp-bootstrap
    $ vendor/bin/wpbootstrap wp-init-composer
    [/code]

    By running the command “vendor/bin/wpbootstrap wp-init-composer” to add the wp-bootstrap commands to composer so that you can call wp-bootstrap easier, this step is not strictly needed.

    LOCALSETTINGS.JSON

    In addition to installing wp-bootstrap, you also need to have a localsettings to tell wp-bootstrap where to find your database, some of the credentials and where to install WordPress (where the web server expects to serve the files from). Note that your’re not really supposed to install WordPress in the same folder as your configuration files. Here’s a sample localsettings.json file:

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

    I think it’s fairly self explanatory, but here it goes:

    • environment is typically one of the values “development”, “staging” or “production”. A description of the environment that this installation is
    • url The url for this installation
    • dbhost, dbname, dbuser and dbpass are the database credentials. Wp-bootstrap assumes that a database already exists and is accessible using those credentials
    • wpuser, wppass are the credentials for the default WordPress admin user.
    • wppath is the path where WordPress will be installed.

    APPSETTINGS.JSON

    The last thing you need to add is an application settings file. The very minimum file you need to provide is:

    [code]
    {
    "title": "TestingComposer approach";
    }
    [/code]

    Title is the only mandatory field in this file, but it’s far from the only one.

    Section: plugins:

    This section consists of two sub arrays “standard” and “local”. Each array contains plugin names that should be installed and activated on the target WordPress site.

    • standard Fetches plugins from the official WordPress repository. If a specific version is needed, specify the version using a colon and the version identifier i.e if-menu:0.2.1
    • local A list of plugins in your local project folder. Plugins are expected to be located in folder projectroot/wp-content/plugins/. Local plugins are symlinked into place in the wp-content folder of the WordPress installation specified by wppath in localsettings.json

    Section: themes

    Similar to the plugins section but for themes.

    • standard Fetches themes from the official WordPress repository. If a specific version is needed, specify the version using a colon and the version identifier i.e footheme:1.1
    • local A list of themes in your local project folder. The themes are expected to be located in folder projectroot/wp-content/themes/. Local themes are symlinked into place in the wp-content folder of the WordPress installation specified by wppath in localsettings.json
    • active A string specifying what theme to activate.

    Section: settings

    A list of settings that will be applied to the WordPress installation using the wp-cli command “option update %s”. Currently only supports simple scalar values (strings and integers)

    Using wp-bootstrap

    The easiest way to use wp-bootstrap is to simply call the binary file that is added to your vendor/bin subfolder. Using the sample files above, you could do this:

    [code]
    # Install WordPress
    $ vendor/bin/wpbootstrap wp-install

    # alternate:
    $ composer wp-install
    [/code]

    After running this command, you should have a fully working WordPress installation, accessible via the url specified in your localsettings.json file. The title of the site should match whatever you specified as the title attribute in the appsettings.json file.

    More Settings

    So far we’ve managed to reproduce what wp-cli can do in three separate commands, good but perhaps not that great. The real power of wp-bootstrap lies in extending appsettings.json with some more settings. Here’s a slightly more advanced example:

    [code]
    {
    "title": "TestingComposer approach",
    "plugins": {
    "standard": [
    "if-menu:0.21",
    "baw-login-logout-menu",
    "wp-cfm",
    "google-analyticator",
    "wpmandrill"
    ],
    "local": [
    "wordpressapp"
    ]
    },
    "themes": {
    "standard": [
    "agama"
    ],
    "active": "agama"
    },
    "settings": {
    "blogname": "New title 2",
    "blogdescription": "The next tagline"
    }
    }
    [/code]

    Using this file, we can customize the WordPress installation with a new command:

    [code]
    # Install plugins, themes etc.
    $ vendor/bin/wpbootstrap wp-setup

    # alternate
    $ composer wp-setup
    [/code]

    Let’s walk through this:

    • In the Plugins section, we specify a number of standard plugins that will be fetched, installed and activated from the WordPress plugin repository. The if-menu plugins will be installed with version 0.21, but the rest of that list will just be whatever version that is the latest in the repository
    • We also install and activate a local plugin that will be symlinked from [project root]/wp-content/plugins into the WordPress installation. This is so that we can include our own plugins developed specifically for this project.
    • The themes section works very similar, the theme agama is added to the installation from the WordPress theme repository and it’s also set as the active theme.
    • And finally, the settings “blogname” and “blogdescription” are overwritten with the values specified. These names corresponds to what the settings are called in the wp_options database table.

    There are more settings…

    If you’re curious enough to try this, I suggest you head on over to the github page for this project. It got some additional settings that you should read up on, especially if you’re keen to manage pages, menus and images in a similar fashion.

    I’m also very curious to hear what you think about this, don’t hesitate to let me know in the comments. You can also reach out to me on Twitter with comments or questions.

     

    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″]

  • WordPress configuration management

    WordPress configuration management

    This is the 4th 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 developer
    4. WordPress configuration management

    In the previous posts in this series we’ve been looking at how to work with Vagrant and WordPress and how to automate setup work using Grunt and WP-CLI. In this posts, we’ll look a little bit on how we can transfer various settings between the WordPress database and into text files in the source code tree. Because as soon as we have the settings in files, we can easily transfer those settings to a target system such as a staging environment or the live site.

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

    WordPress settings

    A Setting is any of the small or large things you change in the Settings menu in the WordPress admin area. The number of blog posts shown on the first page is a setting and so is the site title and the default date format.

    Settings
    Some of the well known settings from the WordPress admin area

     

    WordPress uses the database to store settings into a table named wp_options (at least as long as you are using the standard wp_ prefix). Most of the settings that a core WordPress installation will put into the wp_options table are simple scalar values, a string or a numeric value. But some of the settings consists of larger more complex structs like an array or even arrays containing objects containing arrays. The internal WordPress code makes sure that pretty much anything you can represent in a PHP variable can be stored as a setting. If needed, WordPress uses the native PHP function serialize() to convert any given variable to a text representation suitable for database storage and then unserialize() to convert it back when needed.

    Serializing

    The concept of taking a complex structure and transforming it into a text representation is called seriallization, so no wonder the PHP functions are named as they are. In our ambitions to automate the setup of WordPress, we want to serialize some settings to a text file that we can keep in our source code repository. When we first install a development version of our WordPress site in a new environment, or when we want to deploy it to another environment, we want to take that text file with serialized settings and update the database. To do this we will continue to build on the WordPress skeleton from the previous posts, you’ll find it in the Github repository for this post. To get started with this code repository, please refer to the first post to learn a little bit about Vagrant and how we’re using it. A few notes:

    • This repo uses an evolved version of the Vagrantfile. Only the rows you need to change are present, everything else is moved in to a file in the vagrant/ sub folder.
    • No need to change anytning inside the vagrant/ sub folder, everything it’s taken care of during provisioning.

     We’re going to talk about two different approaches for managing settings in a text file. The first approach is using Gruntfile.js itself, the other approach uses the free plugin WP-CFM.

    Keeping settings in Gruntfile.js

    The most straight forward way would be to use Gruntfile and Wp-cli. The settings themselves will be in the form of Wp-cli statements that will be automatically inserted into the target WordPress installation when the Grunt task wp-setup is executed.

    [code firstline=”36″ title=”wp-setup task in Gruntfile” language=”js” highlight=”47-49″]

    grunt.registerTask(‘wp-setup’, ”, function() {
    ls = getLocalsettings();
    wpcmd = ‘wp –path=’ + ls.wppath + ‘ –allow-root ‘;

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

    shell.exec(wpcmd + ‘option update blogname "New blog title"’);
    shell.exec(wpcmd + ‘option update blogdescription "experimental tagline"’);
    shell.exec(wpcmd + ‘option update posts_per_page "20"’);

    })
    [/code]

    The three highlighted rows will update the Site title (blogname), the tag line (blogdescription) and the ‘Blog pages show at most’ setting (posts_per_page) that are found in WordPress Admin. This is a very manual form of serializing settings to disk and it’s easy to get started with. If you only have a few of them that you need to set, this approach will work but it has a few downsides.

    Obviously, the manual work involved in writing the wp-cli statements in your Grunt file is not very optimal. Easy to forget individual settings, easy to lose the overview etc. The other downside is that changes you make in WordPress admin has no way of automatically find their way into the Gruntfile. You’re in for a lot of manual work. But there is another way.

    WP-CFM

    WP-CFM is a free plugin available in the WordPress plugin repository. It’s name stands for WordPress Configuration Management and it does exactly that: Configuration Management. WP-CFM uses a concept call bundels. A bundle is a group of individual WordPress settings. WP-CFM can Push a bundle to file, meaning that it will read the value of each of the settings in the bundle from the database and store them in a file. And later, WP-CFM can Pull that file back in and restore those values in the database.

    In the Gruntfile above I took the liberty of installing and activating wp-cfm in the WordPress installation in the Vagrant box, so if you’re following along you should already have it in WordPress. This plugin adds a menu item under settings named WP-CFM. The main WP-CFM screen looks like this:

    WP-CFM admin screen

    We want to create a bundle with the same three setting that we handled in the Grunt task above. So we’ll go ahead and click ‘Add Bundle’, name it ‘settings’ and select the individual settings items we need:

    Creating a new bundle in WP-CFM
    Creating a new bundle in WP-CFM (note, the posts_per_page setting is under the fold in this image)

    After the bundle is created and saved, we can click ‘Push’ to store those three settings to disk. You should end up with a text file in /vagrant/www/wordpress-default/wp-content/config named settings.json:

    [code title=”wp-content/config/settings.json” language=”js”]
    {
    "blogdescription": "experimental tagline",
    "blogname": "New blog title",
    "posts_per_page": "20",
    ".label": "settings";
    }
    [/code]

    As you can see, WP-CFM uses a JSON file to store the individual values and stores the file in a predictable location. For fun, we can change the “blogname” setting inside this file and try the Pull button (you probably will need to reload the page for the Pull button to become active). Once the updated settings has been pulled into the database and you’ve reloaded the page, you should see that whatever value you selected for “blogname” now is in the page title.

    A little automation

    The one great thing with WP-CFM that I didn’t mention yet is that it was written with support for Wp-cli right out of the box. WP-CFM adds a command verb to Wp-cli named ‘config’ with sub commands push and pull. We just need to call these two commands from our Gruntfile to automate things. As usual,  a little bit of plumbing is also needed as well, best explained with code, so let’s have a look at the two new Grunt tasks that we’ve added for this post:

    [code title=”Gruntfile.js” language=”js” firstline=”53″]

    grunt.registerTask(‘wp-export’, ”, function() {
    ls = getLocalsettings();
    wpcmd = ‘wp –path=’ + ls.wppath + ‘ –allow-root ‘;
    pwd = shell.pwd();

    shell.mkdir(‘-p’, pwd + ‘/config’);

    // push settings from DB to file
    src = ls.wppath + ‘/wp-content/config/settings.json’;
    trg = pwd + ‘/config/settings.json’;
    shell.exec(wpcmd + ‘config push settings’);
    shell.cp(‘-f’, src, trg);
    });

    grunt.registerTask(‘wp-import’, ”, function() {
    ls = getLocalsettings();
    wpcmd = ‘wp –path=’ + ls.wppath + ‘ –allow-root ‘;
    pwd = shell.pwd();

    shell.mkdir(‘-p’, ls.wppath + ‘/wp-content/config’);

    src = pwd + ‘/config/settings.json’;
    trg = ls.wppath + ‘/wp-content/config/settings.json’;
    shell.cp(‘-f’, src, trg);
    shell.exec(wpcmd + ‘config pull settings’);
    });

    [/code]

    • Line 53, define the task wp-export
    • Line 58, create the /vagrant/config folder unless it already exists
    • Line 63, run the wp-cli command ‘config push’ for the bundle named ‘settings’
    • Line 64, copy the settings file into our local folder /vagrant/config where it will be under source code control

     

    • Line 67, define the taks wp-import
    • Line 72, create the folder www/wordpress-default/wp-content/config unless it already exists
    • Line 76, copy the settings.json file from the project folder into the correct folder in the WordPress installation (where WP-CFM will expect to find it)
    • Line 77, run the wp-cli command ‘config pull’ for the bundle named settings so that each settings is pulled from the file into the database

    Since the WP-CFM plugin was build for automation from the start, our work is reduced to managing the settings file so that we can keep in under source code control. With these two Grunt tasks, we’ve now automated the process for storing WordPress settings in the source code control system.

    A few pitfalls

    Using WP-CFM together with Grunt and wp-cli takes us a long way in terms of creating a fully automated process for managing WordPress.  However, this process isn’t really perfect yet. There are a few issues to look out for when it comes to WP-CFM:

    • Some settings might store the absolute URL for a post or page on the WordPress installation. If that setting is pulled from disk to the database unchanged, the live site might end up with URL references to the development version of the site
    • Some settings contains references to a page, a post or a menu item using the internal database id and the database ID might differ between the development version and the production version.

    These two issues as well as the challenge of moving actual content (pages, images etc) from development to production is going to be covered in future posts in this series. So stay tuned!

     

    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″]

  • 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.

  • Mysql Workbench on Ubuntu 14.10

    As a friendly tip for anyone else who:

    1. Just upgraded to Ubuntu 14.10
    2. Use Mysql Workbench a lot
    3. Use the built in TCP/IP over SSH to connect to remote servers.

    There’s a big chance that you saw this:

    Selection_001

    Problem

    In Ubuntu 14.10 the package python-paramiko was upgraded to 1.15. The package is used by Python apps to create ssh connection. In version 1.15 it seems that paramiko has problem with some servers due to a mismatch in what protocols to support. End result is that your MySQL Workbench cant connect using an ssh connection

    Solution

    Downgrade to python-paramiko 1.10 that was shipped with Ubuntu 14.04.

    Howto

    Run these two commands in the terminal.

    $ wget http://launchpadlibrarian.net/167351511/python-paramiko_1.10.1-1git1build1_all.deb
    $ sudo dpkg -i python-paramiko_1.10.1-1git1build1_all.deb