We recently covered how to do branched deploys to WP Engine with GitHub Actions. Today, let’s explore managing plugin dependencies with Composer when deploying to WP Engine.
Table of contents
It helps if you are familiar with Composer, WPackagist, and Git version control. However, if you are not, here is an excellent resource to get you started: Managing your WordPress site with Git and Composer. Also, these instructions assume you have an existing WordPress site hosted on WP Engine that you are retroactively putting under version control.
If this is your first time setting up a site deployment on WP Engine – we recommend utilizing our step-by-step guide in the User Portal (logged in). It steps you through the SSH key pair generation, as well as generating the GitHub Action YML file.
Be sure to review the WP Engine GitHub Action for Site Deployment documentation, and understand how the workflow utilizes rsync to modify files on the final server.
Here is what we’ll be covering:
- Version control (Git) – you will only need the
wp-content/
directory under version control. We’ll let WP Engine maintain WordPress core automatic updates. - Composer—You will use Composer and WPackagist.org to manage WordPress plugins. Note that it will be your responsibility to manage plugin updates with this Composer setup, and utilizing Smart Plugin Manager or WordPress auto-updates is not covered.
- Bonus: You will learn to install and manage ACF PRO as a Composer dependency.
Overview of project organization
Below is an example of your final GitHub repository. We will explore these in greater detail. (Also, check out the demo codebase on GitHub to follow along with the proposed structure.)
.github/workflows/[dev|staging|production].yml
: These represent our GitHub Action configuration files for deploying our codebase to their corresponding environments. Be sure to become familiar with the WP Engine GitHub Action for Site Deployment, which relies on using rsync to sync the repository files with the targeted server.rsync-config
: These files configure our WP Engine GitHub Action for Site Deployment. The action relies on running a rsync between the GitHub repository and the targeted environment.excludes.txt
: Referenced in the.github/workflows/[dev|staging|production].yml
file as the explicit rsyncFLAGS
. These are any items we want to exclude from being deleted each time our GitHub Action runs a rsync.- Hint: these files likely exist on the final WP Engine server and we do not want to remove them every time an rsync is executed in our GitHub Action.
includes.txt
: Referenced in the.github/workflows/[dev|staging|production].yml
GitHub Action as the explicit rsyncFLAGS
. These are any items we want to include in our GitHub Action rsync.- Hint: these will likely represent the un-ignored items in your project
.gitignore
which we’ll cover below.
- Hint: these will likely represent the un-ignored items in your project
bin/post-deploy.sh
: This is how you pass anySCRIPTS
to the GitHub Action to run commands on the final destination server.- Tip: you can run WP-CLI and Composer install commands on the final WP Engine environment.
plugins/
: You will rely on Composer and WPackagist to install standard and stable plugins. However, we will also show you how you might handle a custom plugin.plugins/demo-plugin
: Represents any custom plugins you may want to version control. You could have as many of these as you like. For example, you could organize your custom functionality asplugins/foo-plugin
,plugins/bar-plugin
.
themes/
: Similar to our plugins, you will likely version control a single theme for the final destination.themes/demo-theme
: Represents a single, custom theme you would have under version control.
.gitignore
: It is critical to tell Git what you want to ignore from being under version control, as well as what you do not want to ignore (yes, this sounds odd, but trust us).composer.json
: Lists your project’s direct dependencies, as well as each dependency’s dependencies, and allows you to pin relative semantic versions for your dependencies.composer.lock
: Allows you to control when and how to update your dependencies.
WP Engine Composer Deploy Demo
Check out the full demo source code for this tutorial and consider following along and forking the repo.
Start by organizing a copy of your WordPress site’s wp-content/
directory to mirror the organization noted above. It is recommended to create this setup on your local computer. You can access a full site backup from WP Engine’s User Portal. It is okay if there are other directories within your wp-content/
directory. You will tell Git what you want to ignore, or not ignore in the next step.
Create a .gitignore
Create a .gitignore
file in your WordPress installation’s wp-content/
directory and place the code below:
.gitignore
(full source)
#---------------------------
# WordPress general
#---------------------------
# Ignore the wp-content/index.php
/index.php
#---------------------------
# WordPress themes
#---------------------------
# Ignore all themes
/themes/*
# DO NOT ignore this theme!
!/themes/demo-theme
#---------------------------
# WordPress plugins
#---------------------------
# Ignore all plugins
/plugins/*
# DO NOT ignore this plugin!
!/plugins/demo-plugin
#---------------------------
# WP MU plugins: these are
# managed by the platform.
#---------------------------
/mu-plugins/
#---------------------------
# WP uploads directory
#---------------------------
/uploads/
#---------------------------
# WP upgrade files
#---------------------------
/upgrade/
#---------------------------
# Composer
#---------------------------
/vendor
auth.json
.env
.env.*
!.env.example
Code language: plaintext (plaintext)
A few key things to note from the code above:
/plugins/*
: this ignores any directories nested within theplugins/
directory.!/plugins/demo-plugin
: overrides the previous/plugins/*
to allow thedemo-plugin
to not be ignored, and instead, it is version-controlled.
/themes/*
: this ignores any directories nested within the themes/ directory.!/themes/demo-theme
: overrides the previous/themes/*
to allow thedemo-theme
to not be ignored, and instead it is version controlled.
You can adjust the demo-plugin
or demo-theme
examples to work with your setup.
Set up Composer with WPackagist integration
Composer allows you to manage your PHP dependencies. WPackagist mirrors the WordPress plugin and theme directories as a Composer repository.
Typically, you could consider utilizing Composer for PSR-4 / PSR-0 namespacing, linting, and unit testing. We’ll only focus on demonstrating how you might pull in some standard WordPress plugins.
Here is a composer.json
that installs a few example plugins from WPackagist: Two Factor, Gutenberg, and WordPress SEO. These are here for demonstration and feel free to replace them with plugins that are standard to your workflow.
composer.json
(full source)
{
"name": "wpe/composer-demo",
"description": "Demo with Composer and deploy to WP Engine.",
"license": "GPL-2.0+",
"type": "project",
"repositories": [
{
"type":"composer",
"url":"https://wpackagist.org",
"only": [
"wpackagist-plugin/*",
"wpackagist-theme/*"
]
}
],
"require": {
"wpackagist-plugin/two-factor": "*",
"wpackagist-plugin/gutenberg": "*",
"wpackagist-plugin/wordpress-seo": "*"
},
"extra": {
"installer-paths": {
"plugins/{$name}/": [
"type:wordpress-plugin"
],
"themes/{$name}/": [
"type:wordpress-theme"
]
}
},
"config": {
"allow-plugins": {
"composer/installers": true
}
}
}
Code language: JSON / JSON with Comments (json)
If you’re just integrating Composer into your project the first time then you’ll likely want to now run composer install
after creating a composer.json
like the one above. This will generate the corresponding composer.lock
file for your project with these new dependencies (and their dependencies).
If this this is your first time integrating WPackagist into your existing Composer project then the key things to note from the code above:
- Add the WPackagist repository under the
repositories
entry (see lines 6-15 in the code above). - Add any plugins or themes you want to install from WPackagist under the
require
key (see lines 17-19 in the code above). Be sure to use thewpackagist-plugin/
orwpackagist-theme/
prefixed vendor name to tell Composer that you intend these to be installed through WPackagist. - Set the
installer-paths
for your plugins and themes under theextra
key to tell Composer where to install your WPackagist dependencies.
Run composer update
to install the new required dependencies (see lines 22-29 in the code above).
How to install ACF PRO with Composer
ACF has some useful information on installing ACF PRO with Composer. We’ll use the composer.json
code above as our starting point. Here are the steps you’ll need to set this up, which we’ll go over in further detail:
- Copy your ACF PRO license key from the Licenses tab. To activate your license via your
wp-config.php
file, add the following line to the file, replacing[key]
with your license key:define( 'ACF_PRO_LICENSE', '[key]'
. - Add the ACF package repository to your
composer.json
. - Install the plugin by running
composer require wpengine/advanced-custom-fields-pro
.
Here is what your final composer.json
file will look:
composer.json
(full source)
{
"name": "wpe/composer-demo",
"description": "Demo with Composer and deploy to WP Engine.",
"license": "GPL-2.0+",
"type": "project",
"repositories": [
{
"type": "composer",
"url": "https://connect.advancedcustomfields.com"
},
{
"type":"composer",
"url":"https://wpackagist.org",
"only": [
"wpackagist-plugin/*",
"wpackagist-theme/*"
]
}
],
"require": {
"wpackagist-plugin/two-factor": "*",
"wpackagist-plugin/gutenberg": "*",
"wpackagist-plugin/wordpress-seo": "*",
"wpengine/advanced-custom-fields-pro": "^6.3"
},
"extra": {
"installer-paths": {
"plugins/{$name}/": [
"type:wordpress-plugin"
],
"themes/{$name}/": [
"type:wordpress-theme"
]
}
},
"config": {
"allow-plugins": {
"composer/installers": true
}
}
}
Code language: JSON / JSON with Comments (json)
There are other ways to install and activate your ACF PRO license, so be sure to check out the full documentation. If you encounter any issues along the way, then send a support message.
Advanced custom fields to build
with WordPress your way.
Set up WP Engine GitHub Action for Composer integration
WP Engine’s GitHub Action for Site Deployment relies on rsync to transfer and synchronize local GitHub repository files to the final WP Engine hosting environment. This is critical to be mindful of when you initially setup your GitHub workflows.
Additionally, since we’re organizing the root of our repository within the wp-content/
directory then we want to be sure that we configure some key deployment options in the final workflow.
production.yml
(full source)
# Deploy to WP Engine Production environment
# https://wpengine.com/support/environments/#About_Environments
name: Deploy to production
on:
push:
branches:
- main
jobs:
Deploy-to-WP-Engine-Production:
runs-on: ubuntu-latest
steps:
- run: echo "Preparing to deploy to WP Engine production"
- uses: actions/checkout@v3
- name: GitHub Action Deploy to WP Engine
uses: wpengine/github-action-wpe-site-deploy@v3
with:
# Deploy vars
# https://github.com/wpengine/github-action-wpe-site-deploy?tab=readme-ov-file#environment-variables--secrets
# The private RSA key you will save in the Github Secrets
WPE_SSHG_KEY_PRIVATE: ${{ secrets.WPE_SSHG_KEY_PRIVATE }}
# Destination to deploy to WPE
# Change to your environment name
WPE_ENV: yourEnvironmentName
# Deploy options
# An optional destination directory to deploy
# to other than the WordPress root.
REMOTE_PATH: "wp-content/"
# Optional flags for the deployment
FLAGS: -azvr --inplace --delete --include-from rsync-config/includes.txt --exclude=".*" --exclude-from rsync-config/excludes.txt
# File containing custom scripts run after the rsync
SCRIPT: wp-content/bin/post-deploy.sh
Code language: YAML (yaml)
In the code above you’ll want to replace some of the deployment variables, like WPE_ENV
and be sure to setup your SSH keys (both the WP Engine SSH Gateway key and your GitHub repository’s private SSH key: WPE_SSH_KEY_PRIVATE
). Again, the helpful WP Engine step-by-step guide can help you here. The key options you will want to pay close attention to are listed in the table below.
Name | Type | Usage |
---|---|---|
REMOTE_PATH | string | Optional path to specify a directory destination to deploy to. Defaults to WordPress root directory on WP Engine. You want this to be wp-content/ . |
FLAGS | string | Set optional rsync flags such as --delete or --exclude-from . Caution: Setting custom rsync flags replaces the default flags provided by this action. Consider also adding the -azvr flags as needed.– a preserves symbolic links, timestamps, user permissions and ownership.– z is for compression– v is for verbose output– r is for recursive directory scanning |
SCRIPT | string | Remote bash file to execute post-deploy. This can include WP_CLI commands for example. Path is relative to the WP root and file executes on remote. This file can be included in your repo, or be a persistent file that lives on your server. |
You will want to pass some rather specific FLAGS
and a custom post-deploy SCRIPT in order to get our targeted setup accurately deploying.
Configure rsync flags
You’ll be running rsync with the --delete
flag, which is destructive and we need to be careful about what we tell it to delete. Below is what you’ll want to put in your rsync-config/excludes.txt
and rsync-config/includex.txt
files.
excludes.txt
(full source)
# Excluding these items from being deleted each rsync
plugins/*
themes/*
mu-plugins/
uploads/
blogs.dir/
upgrade/*
backup-db/*
advanced-cache.php
wp-cache-config.php
cache/*
cache/supercache/*
index.php
mysql.sql
.env
.env.*
auth.json
vendor
Code language: plaintext (plaintext)
includes.txt
(full source)
# Including plugins/themes that we check into
# Git so that the version in GitHub is deployed
/plugins/demo-plugin
/themes/demo-theme
# ...other plugins could go here...
Code language: plaintext (plaintext)
Create a post-deploy script
After everything is deployed, you will want to run composer install
on the WP Engine environment. This will allow you to update your dependencies with Composer locally, commit any changes, push them to the Git remote, and once the GitHub Action is run to rsync any composer.json
and composer.lock
changes then it’ll install any updated dependencies on the final environment. This is the SCRIPT: wp-content/bin/post-deploy.sh
we set in our GitHub Actions’s YML file (above).
post-deploy.sh
(full source)
#!/bin/sh
echo "Starting post deploy script..."
echo "Switch directory to wp-content/"
cd wp-content
echo "Installing Composer dependencies..."
composer install --optimize-autoloader --no-dev --no-progress
Code language: plaintext (plaintext)
Conclusion
Utilizing Composer with WPackagist to manage your WordPress plugin dependencies can help keep teams organized and facilitate consistent workflows.
Let us know how you’re maintaining your ideal workflow—tag us on X @wpengine.