• Overview
    Key features
    • Observability
    • Auto-scaling
    • Multiframework
    • Security
    • Django
    • Next.js
    • Drupal
    • WordPress
    • Symfony
    • Magento
    • See all frameworks
    • PHP
    • Python
    • Node.js
    • Ruby
    • Java
    • Go
  • Industries
    • Consumer Goods
    • Media/Entertainment
    • Higher Education
    • Government
    • Ecommerce
  • Pricing
  • Featured articles
    • Switching to Platform.sh can help IT/DevOps organizations drive 219% ROI
    • Organizations, the ultimate way to manage your users and projects
  • Support
  • Docs
  • Login
  • Request a demo
  • Free Trial
Meet Upsun. The new, self-service, fully managed PaaS, powered by Platform.sh.Try it now
Cover image

A modern development workflow for WordPress

wordpresscomposersource operations
04 March, 2022
Vincenzo Russo
Vincenzo Russo
OEM Business & Technical Development Manager in Sales

To quote my colleague, Chad, WordPress “remained tremendously popular since its release in 2003”. For many, WordPress remains by far the CMS that is easiest to adopt, and that provides a fast time to market in the majority of use cases. There is so much high-quality material out there for WordPress, be it OSS or Premium, that one can have beautiful sites powered by an easy-to-use CMS up and running in no time.

True, but…

There was a time in my career when building CMS solutions for enterprise was the main thing I did. In those circles the idea that WordPress was a toy not suitable for enterprise-grade projects was common. This was especially true when I was working with teams that had already been initiated to best practices that later became known as 12 Factor. The traditional way of “doing WordPress” couldn’t really espouse the 12-Factor way easily.

WordPress, traditionally

Traditionally, a WordPress project’s codebase would consist of the entire WordPress core, plus all the plugins and themes necessary for the project to work. The entire codebase would then be deployed to a hosting of choice, usually via—cough— (S)FTP. The slightly evolved model is that the very same codebase is checked into a SCM system of choice, with a CI tool moving it onto the hosting’s servers.

Navigating WordPress Automatic Background Updates

Automatic Background Updates were introduced in WordPress 3.7 for the WordPress core, and later extended to plugins, themes, and translation files. Whilst a degree of automation for updates is definitely desirable, the way this is implemented in WordPress (i.e., in situ updates) means that if your codebase is in a repository, it’ll quickly get out of date, and you’ll have to manage updates in the repo on the side, to avoid problems and regressions down the road. If instead, you manage everything via FTP alone, it means each update will be very risky anyway. Either way, I can guarantee that things will quickly escalate into a nightmare.

Wait, it’s not all

It gets more complicated. To quote Chad again from the same article:

“Many hosting solutions, Platform.sh included, enforce read-only filesystems at runtime. These solutions deploy a highly reproducible build image as a consequence of your codebase and its explicitly defined build process, all committed to version control. [...] External code (dependencies) [...] and ideally definitions of your infrastructure itself are committed to exact versions so that your entire DevOps process from start to finish is repeatable and reproducible.”

This is excellent also for security reasons. Yet, as you may have gathered, it clashes completely with the way WordPress handles automatic updates, and these might need to be disabled entirely where a read-only file system is employed.

Leveraging Bedrock and Composer for modern WordPress development

In his article, Chad talks about how Bedrock leverages composer to provide a more modern approach to WordPress development, thanks also to the great work behind WordPress Packagist. Chad shows that combining these efforts with our very own Source Operations, it’s possible to achieve a good degree of automation in updates, with greater control on versions and a greater repeatability of the process.

Our Goal: Efficient WordPress workflow and development

The goal of this article is to go one step further, and show how to combine Platform.sh with other tools, to achieve the best WordPress workflow—including auto-updates—that allows also for a greater degree of complexity, control, and configuration.

To do so, I’ll be using a Platform.sh template that I developed starting from our own composer-based WordPress template, before Bedrock came onto the scene.

Maximize automation with a template and WordPress workflow plugins

This template hosts the codebase for two sites (ita and eng), both

  • are built using WordPress.org
  • have a rudimentary “distro” support
  • are deployed on Platform.sh in Multi-App setup
  • have their entire codebase managed via composer, thanks to johnpbloch/wordpress, WordPress Packagist (for plugins and themes), and inpsyde/wp-translation-downloader (a composer plugin to manage WordPress translations for core, plugins, and themes)
  • have their dependencies automatically upgraded by Dependabot
  • have their Dependabot PRs automatically merged by Mergify when builds pass
  • have new code deployed to production automatically on every PR merge
  • use Redis as back-end caching
  • use Cloudflare as CDN
  • use GitHub Actions as additional CI/CD and Cron Scheduler

In addition to the above:


If you are thinking this template was derived from a real-life project, then you’re right!

In the remainder of this article I’ll be focussing on the points that show how this template is all about automating as much of your Wordpress development workflow as possible, and I’ll avoid getting into some other details. Thus, if you want more insights into composer-based WordPress development, do refer back to Chad’s article or directly to the code in my template.

Automating WordPress installation with Distros and Composer

Distros or install profiles are essentially a way to have your own default installation configuration. Whilst some software have built-in support for that, WordPress does not. My goal was to completely automate the installation on the first deployment, so I decided to take matters into my own hands.

The rudimentary support I implemented for this relies on two things. First, a bespoke section in the composer.json file:

  "distro": {
    "default-theme": "lovecraft",
    "enable-plugins": [

Second, a script that uses the information in that section to perform some initial setup:

#!/usr/bin/env bash

cd wordpress
if ! wp core is-installed; then
  WP_URL=$(echo $PLATFORM_ROUTES  | base64 --decode | jq -r 'keys[]' | grep $PLATFORM_APPLICATION_NAME | grep https | grep www)
  wp core install --url="${WP_URL}" --title="Modern WordPress" --admin_user=admin --admin_password=changeme --admin_email=change@me.com
  DEFAULT_THEME=$( jq -r '.[ "distro" ][ "default-theme" ]' ../composer.json )
  wp theme activate ${DEFAULT_THEME}
  jq -r '.[ "distro" ][ "enable-plugins" ][]' ../composer.json |
  while read PLUGIN; do
    wp plugin activate ${PLUGIN}
  wp core update-db

The script is then executed as part of the deploy hook in Platform.sh, i.e. after the build phase has downloaded and built WordPress and the other dependencies via composer. The result will be a fully installed WordPress application, avoiding you from having to go through the default manual (albeit simple) WordPress setup wizard.

If you are wondering why we didn't simply use the scripts.postbuild section in composer.json to run such a script, the primary reason is that during the build phase (when composer is executed) the database service is not yet available, since the build phase is designed only to create a deployable artifact.

Automatic WordPress database updates

We’ll talk about code updates later, but since we have referenced the script above, I wanted to highlight that the same script takes care of updating the database in case there have been code updates that demand such operation to take place.

If you have worked with WordPress before, you know that at the very least, when WordPress core is upgraded, you might be required to run a very simple routine that upgrades the database schema accordingly. This can be done through the administrative UI, which will present you with a simple button to click; or it can be done via the wp-cli. The latter is what this script is using (see how the wp-cli is installed): if WordPress is already installed, on each deploy it will simply run a database update routine, which will only do something if there is something to do.

Automated dependency updates

Part of the GitHub family for quite some time now, Dependabot provides a free plan for public repositories, and it supports PHP+Composer. You can configure it to decide what kind of upgrades you want to perform on your dependencies, and the bot will issue pull requests periodically, avoiding stale dependencies. Our configuration looks like this:

version: 2
  - package-ecosystem: composer
    directory: "/eng"
      interval: daily
    open-pull-requests-limit: 10
      - dependency-name: wpackagist-plugin/really-simple-ssl
          - 4.0.10
  - package-ecosystem: composer
    directory: "/ita"
      interval: daily
    open-pull-requests-limit: 10

For both apps, we have a daily check on dependencies (remember, WordPress core itself is a dependency!), with a limit of maximum 10 open pull requests at any one time. You can also do clever things like ignoring specific versions of a dependency, if you know they are buggy, for example.

'A list of recommended dependencies from Dependabot'

You might ask: ok, but how does opening PRs automatically actually achieve automatic dependency updates? Well, it does not :)

Enter auto-merge

Opening loads of PRs in an automated fashion is hardly going to make your life easier and keep your dependencies up to date effortlessly. Thus, a tool like Dependabot must be combined with another one that provides merge queues and the ability to auto-merge pull requests that meet certain criteria. I used Mergify, but it is likely that in the near future you might be able to use GitHub merge queues if they decide to implement a system similar to Mergify, where you can define a pattern for the PRs that must be auto-merged:

  - name: automatic merge for Dependabot pull requests
      - author~=^dependabot(|-preview)\[bot\]$
      - status-success=platformsh
        method: squash

The configuration above essentially instructs Mergify to automatically squash-merge all PRs issued by Dependabot and that have been built successfully on Platform.sh.

As I mentioned already, this template is meant to be used via GitHub integration with Platform.sh. This makes it possible for every PR raised by Dependabot to have an associated development environment where the build and deployment of the application with the updated dependencies will take place. Thanks to the integration with GitHub, this process is added as a status check for the PRs on the repository. That status check is what Mergify uses here to make sure that everything is fine with the PR; if it is, the PR will be merged.

This, of course, is a very basic configuration; nothing is stopping us from using additional status-success conditions in the configuration, which could be unit tests run by a CI and other things like this. The more automation and status checks you have, the more confident you can be that the PR can be automatically merged.

Achieving control and assurance with Platform.sh and automation tools

Combining tools like Dependabot, Mergify and Platform.sh gives you a much greater degree of control and assurance over your process of automated updates for WordPress core, plugins, themes, and translation files. This is because for each update you can be certain that a live-like environment will be built with the changes, and additional tests can be run to make sure that everything still works just fine. You can decide whether you want to auto-update just minor versions or also major versions. You can exclude specific versions or specific items (a particular plugin or theme, for instance). And much more. You have finer-grained control, more power, and a higher degree of assurance.

Further Developments

The WordPress development workflow I’ve shown you here can be applied to extended scenarios. For instance, you can configure Mergify to auto-merge other or even all types of PRs, given the right conditions (remember that even manual peer reviews and other manual steps can be added as status checks). You can also extract this workflow and apply it to other type of applications, not just WordPress.

However, one way one could really take this to another level is by automating infrastructure upgrades! All you’d need is a way to check if there’s a new release of one of the Platform.sh managed services you use in your project, and then issue a new PR with the update (just like Dependabot does with application dependencies). Once you have that component (which could be implemented within your external CI tool, such as GitHub Actions), then you could configure Mergify to auto-merge those PRs, again, given the right conditions.

Start WordPress development workflow automation with Platform.sh

Whilst you wait for the ability to auto-upgrade your infrastructure (in fact, I promise I’ll be updating my template with that very feature as soon as it becomes possible to do so), you can still start using this template and this workflow right now, and begin saving precious time to your development team:

And as usual, you know where to find us, if you need us!

Get the latest Platform.sh news and resources

Related Content

Meeting Jonny Harris: WordPress performance optimization with Blackfire

Meeting Jonny Harris: WordPress performance optimization with Blackfire

AboutSecurity and complianceTrust CenterCareersPressContact us
Thank you for subscribing!
Field required
Leader Winter 2023
System StatusPrivacyTerms of ServiceImpressumWCAG ComplianceAcceptable Use PolicyManage your cookie preferencesReport a security issue
© 2024 Platform.sh. All rights reserved.
Supported by Horizon 2020's SME Instrument - European Commission 🇪🇺