Adding PR Preview Buttons with GitHub Actions
The Playground PR Preview action adds a preview button to your pull requests. Clicking the button launches Playground with your plugin or theme installed from the PR branch:

For complete configuration options and advanced features, see the action-wp-playground-pr-preview workflow README.
How it works
The action runs on pull request events (opened, updated, edited). It can either update the PR description with a preview button or post the button as a comment.
Basic setup for plugins
For plugins without a build step, create .github/workflows/pr-preview.yml:
name: PR Preview
on:
pull_request:
types: [opened, synchronize, reopened, edited]
jobs:
preview:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- name: Post Playground Preview Button
uses: WordPress/action-wp-playground-pr-preview@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
mode: 'append-to-description'
plugin-path: .
The plugin-path: . setting points to your plugin directory. For subdirectories like plugins/my-plugin, use plugin-path: plugins/my-plugin.
See adamziel/preview-in-playground-button-plugin-example for a live example of this workflow in action.
Basic setup for themes
For themes, use theme-path instead of plugin-path:
name: PR Preview
on:
pull_request:
types: [opened, synchronize, reopened, edited]
jobs:
preview:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- name: Post Playground Preview Button
uses: WordPress/action-wp-playground-pr-preview@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
theme-path: .
Button placement
By default, the action updates the PR description (mode: append-to-description). To post as a comment instead:
with:
plugin-path: .
mode: comment
github-token: ${{ secrets.GITHUB_TOKEN }}
The action wraps the button in HTML markers and updates it on subsequent runs. By default, it restores the button if you remove it. To prevent restoration:
with:
plugin-path: .
restore-button-if-removed: false
Working with built artifacts
For plugins or themes requiring compilation, the workflow involves building the code, exposing it via GitHub releases, and creating a blueprint that references the public URL.
Example workflow (see complete documentation):
name: PR Preview with Build
on:
pull_request:
types: [opened, synchronize, reopened, edited]
permissions:
contents: write
pull-requests: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build
run: |
npm install
npm run build
zip -r plugin.zip dist/
- uses: actions/upload-artifact@v4
with:
name: built-plugin
path: plugin.zip
expose-build:
needs: build
runs-on: ubuntu-latest
permissions:
contents: write
outputs:
artifact-url: ${{ steps.expose.outputs.artifact-url }}
steps:
- name: Expose built artifact
id: expose
uses: WordPress/action-wp-playground-pr-preview/.github/actions/expose-artifact-on-public-url@v2
with:
artifact-name: 'built-plugin'
pr-number: ${{ github.event.pull_request.number }}
commit-sha: ${{ github.sha }}
artifacts-to-keep: '2'
create-blueprint:
needs: expose-build
runs-on: ubuntu-latest
outputs:
blueprint: ${{ steps.blueprint.outputs.result }}
steps:
- uses: actions/github-script@v7
id: blueprint
with:
script: |
const blueprint = {
steps: [{
step: "installPlugin",
pluginZipFile: {
resource: "url",
url: "${{ needs.expose-build.outputs.artifact-url }}"
}
}]
};
return JSON.stringify(blueprint);
result-encoding: string
preview:
needs: create-blueprint
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- uses: WordPress/action-wp-playground-pr-preview@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
blueprint: ${{ needs.create-blueprint.outputs.blueprint }}
The artifacts-to-keep setting controls how many builds to retain per PR. For themes, change installPlugin to installTheme.
See adamziel/preview-in-playground-button-built-artifact-example for a complete working example.
Custom blueprints
Use blueprints to configure the Playground environment. You can install additional plugins, set WordPress options, import content, or run custom PHP.
Example installing your plugin with WooCommerce:
jobs:
create-blueprint:
name: Create Blueprint
runs-on: ubuntu-latest
outputs:
blueprint: ${{ steps.blueprint.outputs.result }}
steps:
- name: Create Blueprint
id: blueprint
uses: actions/github-script@v7
with:
script: |
const blueprint = {
steps: [
{
step: "installPlugin",
pluginData: {
resource: "git:directory",
url: `https://github.com/${context.repo.owner}/${context.repo.repo}.git`,
ref: context.payload.pull_request.head.ref,
path: "/"
}
},
{
step: "installPlugin",
pluginData: {
resource: "wordpress.org/plugins",
slug: "woocommerce"
}
}
]
};
return JSON.stringify(blueprint);
result-encoding: string
preview:
needs: create-blueprint
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- uses: WordPress/action-wp-playground-pr-preview@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
blueprint: ${{ needs.create-blueprint.outputs.blueprint }}
Or reference an external blueprint:
with:
blueprint-url: https://example.com/path/to/blueprint.json
See Blueprints documentation for all available steps and configuration options.
Template customization
Customize the preview content using template variables:
with:
plugin-path: .
description-template: |
### Test this PR in WordPress Playground
{{PLAYGROUND_BUTTON}}
**Branch:** {{PR_HEAD_REF}}
Available variables: {{PLAYGROUND_BUTTON}}, {{PLUGIN_SLUG}}, {{THEME_SLUG}}, {{PR_NUMBER}}, {{PR_TITLE}}, {{PR_HEAD_REF}}, and more.
See the workflow README for the complete list.
Artifact exposure
The expose-artifact-on-public-url action uploads built files to a single release (tagged ci-artifacts by default). Each artifact gets a unique filename like pr-123-abc1234.zip. Old artifacts are automatically cleaned up based on artifacts-to-keep.
Configuration options: Expose Artifact Inputs
Troubleshooting
Button not appearing: Workflow file must exist on the default branch. Check Actions tab for errors.
Preview fails to load: Verify path points to valid plugin/theme directory. Check build logs for artifacts.
Not activated: Check browser console for PHP errors. Dependencies may be missing.
Permissions errors: Set permissions at job level.
More: workflow README
Examples
- WordPress/blueprints - Blueprint previews
- adamziel/preview-in-playground-button-plugin-example - Plugin without build
- adamziel/preview-in-playground-button-built-artifact-example - Plugin with build