There are a lot of ways in which a WordPress GitHub integration can be helpful in WordPress development and project collaboration. One of them is in deploy routines with automatic deployments, instead of the cowboy coding approach, using FTP, manually grabbing our themes and/or plugin files, and uploading them manually using software like FileZilla, we can deploy directly from GitHub to our live WordPress site.
That's why I wrote this post and, as always, to record what I did for when I forget it in a few months from now.
We will review how to set up a WordPress GitHub integration to manage the deployment of our WordPress themes and WordPress plugins, which can save us a lot of time and is especially important if we are using custom themes and plugins.
We will not cover:
The WordPress Core: Well, we should never edit core WordPress files, so it doesn't make sense to include the core files in our repository.
The database: Trying to version control the WordPress database opens up a can of worms and we will not open that now.
WordPress development of plugins and themes: I am assuming you have this done, ready to deploy.
Let's get started with the sample workflows we will gonna use to synchronize our WordPress themes and plugins!
Deploying a WordPress Theme
The following .yml code is used to synchronize the theme files you coded, with the /wp-content/themes folder in your server. For a LAMP server hosted in a company like Digital Ocean, that's a sample workflow:
name: Deploy Theme
on:
push:
branches: [master]
env:
SSH_USER: ${{ secrets.SSH_USER }}
SSH_HOST: ${{ secrets.SSH_HOST }}
jobs:
deploy:
name: Deploy WordPress Theme on Digital Ocean
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set SSH Connection
run: |
mkdir -p ~/.ssh/
echo "$SSH_KEY" > ~/.ssh/deploy.key
chmod 600 ~/.ssh/deploy.key
cat >>~/.ssh/config <<END
Host digitalocean
HostName $SSH_HOST
User $SSH_USER
IdentityFile ~/.ssh/deploy.key
StrictHostKeyChecking no
END
env:
SSH_KEY: ${{ secrets.DEPLOY_KEY }}
- name: Sync theme files
run: "rsync --delete -avO
--exclude /deploy_key \
--exclude /.git/ \
--exclude /.github/ \
./ ${{ env.SSH_USER }}@${{ env.SSH_HOST }}:${{ env.DEST }}"
env:
SSH_HOST: digitalocean
# That's the most commom path in a WordPress instalation on a LAMP stack,
# but you can change the destination according to your needs.
DEST: "/var/www/your-domain/wp-content/themes/theme-folder"
Workflow name
In the first line we have the workflow name name: Deploy Theme
.
Workflow triggers
Later, we have the trigger definition, in this case, whenever I push a commit to the master branch on the repository with my WordPress theme, the workflow will be triggered. You can custom that, for more details, you can refer to GitHub documentation.
on:
push:
branches: [master]
Secrets
I create variables for the custom secrets. More info here.
env:
SSH_USER: ${{ secrets.SSH_USER }}
SSH_HOST: ${{ secrets.SSH_HOST }}
Jobs
The jobs section in a GitHub Actions workflow file defines one or more jobs to be executed when a workflow is triggered.
jobs:
deploy:
name: Deploy WordPress Theme on Digital Ocean
runs-on: ubuntu-latest
In the case above:
- deploy is the name of the job, which can be customized to describe the job's purpose.
name is an optional field we use to making it more understandable when viewing the workflow.
runs-on specifies the type of virtual environment or runner on which the job will be executed. In this case, it uses the ubuntu-latest runner, indicating that the job runs on the latest available version of the Ubuntu operating system.
Steps
The steps section in a GitHub Actions workflow file defines a series of individual tasks that are executed as part of a job.
steps:
- name: Checkout
uses: actions/checkout@v2
In the case above:
- steps: contains a list of actions to be executed in the specified order.
- name: is an optional field we use to making it more understandable when viewing the workflow.
- uses: Specifies the action to be performed. In this example, the actions/checkout@v2 action is used to check out the source code repository.
Setting SSH Conection
This is the section of your workflow responsible to sets up an SSH connection for secure access to our remote host.
name: Set SSH Connection
run: |
mkdir -p ~/.ssh/
echo "$SSH_KEY" > ~/.ssh/deploy.key
chmod 600 ~/.ssh/deploy.key
cat >>~/.ssh/config <<END
Host digitalocean
HostName $SSH_HOST
User $SSH_USER
IdentityFile ~/.ssh/deploy.key
StrictHostKeyChecking no
END
env:
SSH_KEY: ${{ secrets.DEPLOY_KEY }}
- name: as in the previous parts, it's a optional field making it more understandable for us, ins this case we will see: Set SSH Connection.
-
run defines the steps or shell commands to execute. In this case:
- Creates the ~/.ssh/ directory if it doesn't already exist.
- Writes the SSH key, stored in the SSH_KEY environment variable, to ~/.ssh/deploy.key.
- Sets the permissions of ~/.ssh/deploy.key to ensure it's only accessible by the user.
- Appends SSH configuration to ~/.ssh/config, including the hostname, username, and path to the SSH key.
- Additionally, it disables strict host key checking for the "digitalocean" host.
- env section specifies environment variables used in the workflow, in this case, it defines the SSH_KEY variable and retrieves its value from a GitHub secret (DEPLOY_KEY).
Syncing the theme files:
This syncing section is responsible for syncing theme files to the remote server using the rsync command. In some hosts, may be necessaire to install manually rsync.
- name: Sync theme files
run: "rsync --delete -avO
--exclude /deploy_key \
--exclude /.git/ \
--exclude /.github/ \
./ ${{ env.SSH_USER }}@${{ env.SSH_HOST }}:${{ env.DEST }}"
The rsync command performs the following tasks:
--delete: Ensures that files deleted locally are also deleted on the remote server.
-avO: Sets rsync options for archive mode, verbose output, and optimization.
--exclude: Specifies which files or directories to exclude from the synchronization. In this example, it excludes the /deploy_key, /.git/, and /.github/ folders, but you can customize according to your project.
./: Specifies the source directory to sync from, which is the current directory of the workflow.
${{ env.SSH_USER }}@${{ env.SSH_HOST }}:${{ env.DEST }}:
Specifies the destination for the synchronization. It uses environment variables for the SSH username, host, and destination path.
The var definition
In this section there are some other environment variables that are used within the workflow.
env:
SSH_HOST: digitalocean
# That's the most commom path in a WordPress instalation on a LAMP stack,
# but you can change the destination according to your needs.
DEST: "/var/www/your-domain/wp-content/themes/theme-folder"
Deploying a WordPress Plugin
To deploy a plugin, you can follow the same idea above, just changing the deploy path to /var/www/your-domain/wp-content/plugins/plugin-folder
The sample workflow below:
name: Deploy Plugin
on:
push:
branches: [master]
env:
SSH_USER: ${{ secrets.SSH_USER }}
SSH_HOST: ${{ secrets.SSH_HOST }}
jobs:
deploy:
name: Deploy WordPress Plugin on Digital Ocean
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set SSH Connection
run: |
mkdir -p ~/.ssh/
echo "$SSH_KEY" > ~/.ssh/deploy.key
chmod 600 ~/.ssh/deploy.key
cat >>~/.ssh/config <<END
Host digitalocean
HostName $SSH_HOST
User $SSH_USER
IdentityFile ~/.ssh/deploy.key
StrictHostKeyChecking no
END
env:
SSH_KEY: ${{ secrets.DEPLOY_KEY }}
- name: Sync plugin files
run: "rsync --delete -avO
--exclude /deploy_key \
--exclude /.git/ \
--exclude /.github/ \
./ ${{ env.SSH_USER }}@${{ env.SSH_HOST }}:${{ env.DEST }}"
env:
SSH_HOST: digitalocean
# That's the most commom path in a WordPress instalation on a LAMP stack,
# but you can change the destination according to your needs.
DEST: "/var/www/your-domain/wp-content/plugins/plugin-folder"
That's my repository with some sample workflows customized for different servers. Be free to contribute through pull requests adding more workflows or even suggest improvements to the current ones. If that was useful for you, please consider leaving a star in the repository.
References and special thanks to:
Top comments (0)