How to Set Up a WordPress Playground Live Demo for Your Plugin (Nginx, Cloudflare, .htaccess)

How to Set Up a WordPress Playground Live Demo for Your Plugin (Nginx, Cloudflare, .htaccess)

Codeable.io

A live demo is the best “Try it free” button a plugin can have. Visitors click once and get a working WordPress site in their browser, with your plugin active and sample data ready. No install, no signup, no risk.

WordPress Playground makes this possible, but if you host the files yourself (and not on WordPress.org), there is one step that trips most people up: CORS. This guide walks through the whole setup, step by step, using Nginx. If you use Cloudflare or Apache, there are alternatives for that step too.

How it works

Playground runs WordPress inside the visitor’s browser. You control what it loads with a small JSON file called a blueprint. The blueprint tells Playground which plugin to install, which files to add and which page to open first. You then link to Playground with your blueprint URL, and it builds the demo on the fly.

You need three files on your own server:

  • blueprint.json, the instructions
  • The plugin ZIP, for example my-plugin-1.0.0.zip
  • An optional ZIP of sample data, for example uploads for a media plugin

We will use Media Library Recovery as the example. Its demo needs images in the uploads folder that are not in the Media Library, so we add a ZIP of sample uploads.

Step 1: Prepare the plugin ZIP

Build a normal installable ZIP with the plugin folder at the top level, like the one you would upload in Plugins > Add New. Include any compiled CSS and JavaScript, because Playground does not run your build.

plugin-name-1.0.0.zip
  plugin-name-1.0.0/
    plugin-name.php
    assets/dist/...
    inc/...

Only use a free or demo version here. Anything in a public Playground blueprint can be downloaded by anyone who reads the URL.

Step 2: Prepare the sample data (optional)

If your plugin needs content to show off, put it in a ZIP. For Media Library Recovery, we zipped the files from a local site’s wp-content/uploads folder, keeping the year/month folders. The files are in the folder, but not in the database, which is the exact case the plugin recovers.

mlr-uploads.zip
  2024/03/bus-ride.jpg
  2024/03/city-bicycle.png
  2025/01/...

Keep it small. Playground downloads it every time someone opens the demo, so a few megabytes is plenty.

Step 3: Write the blueprint

Create blueprint.json. This one logs in as admin, installs and activates the plugin, unzips the sample uploads and opens the plugin’s main page.

{
  "$schema": "https://playground.wordpress.net/blueprint-schema.json",
  "landingPage": "/wp-admin/admin.php?page=plugin_slug",
  "preferredVersions": { "php": "8.2", "wp": "latest" },
  "phpExtensionBundles": ["kitchen-sink"],
  "features": { "networking": true },
  "steps": [
    {
      "step": "login",
      "username": "admin",
      "password": "password"
    },
    {
      "step": "installPlugin",
      "pluginZipFile": {
        "resource": "url",
        "url": "https://example.com/playground/plugin-name-1.0.0.zip"
      },
      "options": { "activate": true }
    },
    {
      "step": "unzip",
      "zipFile": {
        "resource": "url",
        "url": "https://example.com/playground/mlr-uploads.zip"
      },
      "extractToPath": "/wordpress/wp-content/uploads"
    }
  ]
}

Change landingPage to the admin page you want visitors to see first. You can copy the slug from the URL of your plugin’s settings page.

Step 4: Upload the three files

Create a folder on your server, for example https://example.com/playground/, and upload the blueprint, the plugin ZIP and the sample data ZIP into it. Open each URL in your browser to check that it downloads or loads.

If you try the demo now, it will fail. Browsers block Playground from reading files on another domain unless that server allows it. That permission is the CORS header, and we add it next.

Step 5: Add the CORS header with Nginx

Open your site’s Nginx configuration and add a location block for the folder, inside the server block of your domain:

location /playground/ {
    add_header Access-Control-Allow-Origin "*" always;
}

Test the configuration and reload Nginx:

sudo nginx -t
sudo systemctl reload nginx

The always keyword makes Nginx send the header on every response, not just successful ones. If your config already has a block for static files, such as location ~* \.(zip|json)$, that block can win over the one above. In that case, add the same add_header line inside it.

Alternative A: Cloudflare Snippet

If your domain is behind Cloudflare and you cannot edit the server config, add the header at the edge with a Snippet.

  1. In the Cloudflare dashboard, select your domain and go to Rules > Snippets > Create Snippet.
  2. Name it playground_cors and paste this code:
export default {
  async fetch(request) {
    const response = await fetch(request);
    const newResponse = new Response(response.body, response);
    newResponse.headers.set("Access-Control-Allow-Origin", "*");
    return newResponse;
  },
};
  1. Under Snippet rule, choose a custom filter expression and enter:
starts_with(http.request.uri.path, "/playground/")
  1. Click Deploy.

Do not use both Nginx and Cloudflare to set the same header. A duplicated Access-Control-Allow-Origin header is rejected by browsers.

Alternative B: .htaccess on Apache or LiteSpeed

On Apache or LiteSpeed hosting, create a file named .htaccess inside the playground folder with this content:

<IfModule mod_headers.c>
    Header set Access-Control-Allow-Origin "*"
</IfModule>

No restart is needed. The rule applies to every file in that folder right away.

Step 6: Check the header

Before you open Playground, confirm the header is sent for all three files. Run this for each one:

curl -I -H "Origin: https://playground.wordpress.net" https://example.com/playground/blueprint.json

Look for Access-Control-Allow-Origin: * in the response. If it is missing, see the troubleshooting list at the end.

Step 7: Launch the demo

Your demo link is the Playground address plus your blueprint URL:

https://playground.wordpress.net/?blueprint-url=https://example.com/playground/blueprint.json

Open it. After a few seconds you should land on your plugin’s page, logged in and ready to try. Then use the same link as the target of a “Live Demo” button on your site:

<a href="https://playground.wordpress.net/?blueprint-url=https://example.com/playground/blueprint.json" target="_blank" rel="noopener">Live Demo</a>

Troubleshooting

  • Header missing in curl: the config was not reloaded, or another location block is handling the files. Add the add_header line there.
  • Header present but the demo still fails: open the browser console. A message about a duplicate Access-Control-Allow-Origin means two layers set it. Keep only one.
  • Old files load after an update: purge the cache for those files in Cloudflare, or rename the ZIP with the new version number and update the blueprint.
  • Plugin does not activate: make sure the plugin folder is at the top level of the ZIP and the compiled assets are included.
  • Blueprint 404: check the file name and that the URL opens in a normal browser tab.

Can I protect the plugin ZIP?

Not really. Playground downloads the ZIP from the visitor’s browser, so the file has to be public. Use this setup for free or demo versions only, and keep paid versions out of public blueprints.

Leave a Reply

Your email address will not be published. Required fields are marked *