Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Use a GitHub Actions workflow that runs when a designated branch receives a push, validates the theme, and copies only that theme into the WordPress site’s wp-content/themes/<theme-folder>/ directory. Store the SSH private key in GitHub Secrets, protect production with a GitHub Environment, and prevent overlapping deployments with concurrency controls.

What the deployment pipeline does

A safe theme-only pipeline has five stages:

  1. A commit reaches an environment branch, such as staging or main.
  2. GitHub Actions checks out the repository.
  3. The workflow validates PHP and builds any required CSS or JavaScript.
  4. An SSH-authenticated deployment step transfers the theme directory to the matching remote directory.
  5. You review the Actions log and the host’s deployment status, then clear relevant caches if needed.

Keeping the source and destination limited to one theme reduces the chance of changing WordPress core, uploads, plugins, configuration, or unrelated themes.

Prepare the repository and branches

Keep the theme in a predictable directory

Place the deployable theme at a stable path such as wp-content/themes/genesis-child-theme/. Decide whether compiled CSS and JavaScript are committed to Git or generated during the workflow; either approach can work, but the deployment must transfer the files the site actually needs.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Map branches to environments

Use a staging branch for automatic staging releases and reserve main for production, or choose another mapping that matches your release process. A push trigger starts the workflow only after the commit has reached the selected branch. Add workflow_dispatch when an operator should be able to start a deployment manually.

Create the GitHub Actions workflow

Save a workflow file under .github/workflows/. This skeleton shows the trigger, validation job, deployment boundary, and serialization controls; the host-specific deployment action belongs in the marked deployment step.

name: Deploy WordPress theme

on:
  push:
    branches:
      - staging
      - main
  workflow_dispatch:

concurrency:
  group: wordpress-theme-${{ github.ref }}
  cancel-in-progress: false

jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Validate theme
        run: |
          find wp-content/themes/genesis-child-theme -name '*.php' -print0 |
            xargs -0 -n1 php -l
          # Run your CSS/JavaScript build here, if the theme requires one.

  deploy:
    needs: validate
    runs-on: ubuntu-latest
    environment:
      name: ${{ github.ref_name == 'main' && 'production' || 'staging' }}
    steps:
      - uses: actions/checkout@v4
      - name: Deploy the theme
        # Add the deployment action or SSH/rsync implementation supplied by your host.
        run: echo "Configure the host-specific deployment step here"

The concurrency group keeps two runs for the same branch from deploying at once. Setting cancel-in-progress: false lets an earlier deployment finish instead of being interrupted; choose a different policy only after considering how your host handles partial updates.

Authenticate without exposing credentials

Generate or obtain an SSH key pair accepted by the WordPress host. Store only the private key in a GitHub repository or organization secret, and install the matching public key on the host with the narrowest access it supports. Never commit the private key or print it in a workflow log.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

WP Engine’s documented integration expects the private key in a secret named WPE_SSHG_KEY_PRIVATE and connects through its SSH Gateway. Other hosts and actions use different secret names, connection details, and destination settings.

Configure a host-specific deployment step

WP Engine example

WP Engine documents wpengine/github-action-wpe-site-deploy, an action that uses the WP Engine SSH Gateway and rsync. Configure its source as the repository theme directory, for example wp-content/themes/genesis-child-theme/, and its destination as the corresponding remote theme directory. Follow the action’s current Marketplace documentation for the exact input names and version.

That action supports PHP syntax checking through its PHP_LINT option. If your theme has a front-end build, run that build before the transfer and make clear whether generated files are committed or created in CI.

Other hosts

A different provider may support ordinary SSH and rsync, a maintained GitHub integration, or neither. Confirm all of the following before relying on automatic deployment:

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • The host permits SSH or its documented deployment method.
  • The remote theme path is correct and writable by the deployment account.
  • The GitHub-hosted runner can reach the host and its SSH gateway.
  • The provider does not require an IP allowlist, private network, or special firewall route that GitHub-hosted runners cannot satisfy.

If the site is reachable only from a private network, use a properly secured self-hosted runner or the provider’s supported alternative. GitHub-hosted runner traffic can originate from a broad range of IP addresses.

Get source and destination paths right

Deploy the contents of the theme directory, not the whole repository. For example, the source should be the repository’s wp-content/themes/genesis-child-theme/ directory and the remote target should be that site’s matching theme directory.

Check trailing-slash behavior before the first production run. WP Engine documents that a trailing slash copies the contents of the selected source directory, while omitting it copies the directory itself and its contents. A path mismatch can create an extra nested theme directory or leave WordPress loading old files.

Handle exclusions and deletion flags carefully

Exclude development-only files and anything outside the theme’s release, such as local environment files, logs, and build caches. Keep uploads, configuration, plugins, and unrelated themes outside the deployment scope.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

WP Engine documents a non-destructive default. Its custom FLAGS replace the default flags, and an example containing --delete can remove remote files that no longer exist in the source. Use deletion only when you intentionally want the remote directory to mirror the repository and have verified the consequences.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Protect production releases

Create GitHub Environments named staging and production. Environment rules can:

  • Restrict which branches are allowed to deploy.
  • Scope deployment secrets to the intended environment.
  • Require one or more reviewers before a production job proceeds.
  • Record deployment status separately from ordinary workflow runs.

A practical arrangement is automatic deployment from staging and a production job on main that pauses for approval. Keep concurrency keyed to the target environment so separate environments do not block one another unnecessarily, while duplicate runs for one environment remain serialized.

Validate before transferring files

PHP syntax

Lint every PHP file in the theme, either with the host action’s PHP_LINT support or a command such as php -l in the validation job. Syntax errors should stop the workflow before any files reach the site.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Front-end output

If the theme uses a CSS or JavaScript build, install its locked dependencies and produce the deployable output before the transfer. Do not assume the host will run Node, package managers, or other build tools unless its documentation says so.

Scope checks

Review the files selected for transfer and confirm that the source directory contains the intended theme, not a parent repository directory. A dry run, where the chosen action supports one, is useful for detecting path and exclusion mistakes before changing production.

Verify and recover after a deployment

  1. Open the workflow run and inspect the validation and transfer logs.
  2. Check the host’s deployment history or SSH transfer status.
  3. Load the site and exercise the changed templates, styles, scripts, menus, and responsive layouts.
  4. Clear WordPress page or CDN caches when the host or caching layer requires it.
  5. If the result is wrong, stop further automatic runs, identify the last known-good commit, and redeploy that commit through the same controlled process.

The WP Engine rsync-style example updates files in place. The official material for this workflow does not establish atomic release switching or automatic rollback, so do not promise those capabilities unless your chosen host and deployment design explicitly provide them.

Common design choices

Choice Advantages Risks or limits
Theme-only transfer Limits the blast radius to the custom theme. Does not deploy plugin, configuration, database, or upload changes.
Automatic staging deployment Quick feedback after a branch push. A bad commit can reach staging without a human click.
Approved production deployment Reviewers can inspect the commit before release. Requires an approval step and a configured GitHub Environment.
GitHub-hosted runner No runner maintenance. May not pass a private-network route or fixed-IP allowlist.
Self-hosted runner Can operate inside a protected network. Adds runner patching, hardening, and access-management responsibilities.

Final checklist

  • The selected branch represents the intended environment.
  • The workflow runs on push and, if needed, workflow_dispatch.
  • The SSH private key is a GitHub secret, never a repository file.
  • The public key and remote permissions are configured on the host.
  • Validation completes before deployment.
  • The source and destination both identify the correct theme directory.
  • Trailing-slash behavior is understood.
  • Exclusions protect local-only files and unrelated WordPress data.
  • Any --delete or equivalent flag has been deliberately reviewed.
  • Production uses environment restrictions, approvals, and suitable concurrency.
  • The runner can reach the host.
  • Logs, deployment history, site behavior, and caches are checked after release.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.