← Back to blog

How to build a WordPress plugin demo site visitors cannot take apart

The SandyWP team 7 min read

Give every visitor their own throwaway WordPress install rather than one shared demo, and turn off the plugin installer and the file editor inside it. That second half is the part every guide on this topic skips, and it is the part that decides whether your premium plugin stays yours.

This post covers both: why the shared demo breaks, what an admin account can actually walk out with, and the four steps to build a per-visitor demo.

Why the one shared demo always breaks

The usual setup is a single WordPress install at demo.yourplugin.com, with demo / demo in the footer and a cron job that resets it every night.

It fails in three predictable ways.

The homepage fills up with somebody else's typing. Three drafts called "test", a widget dragged out to see what happened, and settings changed by a visitor who was curious rather than malicious.

The reset is a promise, not a guarantee. It holds until the cron misses a run, and then your plugin sits deactivated over a weekend while prospects meet a broken site.

And the credentials stop working. One visitor changes the password to see whether they can, and every evaluation after that stops at the login screen.

All three come from the same root cause: one install, shared by strangers, with the state carried from one visitor to the next.

The part nobody writes about: your demo admin is a download page

Read the popular guides on this and you will find a lot on hosting and staging plugins, and nothing at all on this.

InstaWP's guide is around 7,000 words and does not mention it. BlogVault's covers five ways to build a demo site and does not mention it either. Neither one names DISALLOW_FILE_MODS.

Here is the problem. A WordPress admin account is not a viewing account. It is a code-execution account.

Anyone sitting in wp-admin on your demo can open Tools → Plugin File Editor and read the full PHP source of every file in your premium plugin, straight in the browser. They can install a file-manager plugin from the directory and download your plugin folder as a ZIP. They can upload a plugin of their own and run whatever it contains on your server.

If your demo exists to show off a paid product, you have published that product's source with a login form in front of it. The login form is in the footer.

What DISALLOW_FILE_MODS actually blocks

WordPress has a switch for this, and it belongs in every demo's wp-config.php:

define( 'DISALLOW_FILE_MODS', true );

The WordPress documentation describes it plainly: it "will block users being able to use the plugin and theme installation/update functionality from the WordPress admin area", and it "also disables the Plugin and Theme File editor", so you do not need DISALLOW_FILE_EDIT alongside it.

That closes the three easy doors at once. No installer, no ZIP upload, no in-browser source viewer.

Be honest about what it does not do. It is not a licence-enforcement mechanism, and it does not make your PHP unreadable to someone who already has server access. Anything you shipped as unminified JavaScript or CSS was always readable, because the browser has to read it too.

What it does is remove the paths that take thirty seconds and no skill. That is most of the risk on a public demo.

The catch is that it is a wp-config.php constant. Editing that file by hand for every demo you hand out is not a workflow, which is why per-visitor demos and this switch have to arrive together.

One demo per visitor

The fix for all of the above is the same: stop sharing the install.

Stage the site once, exactly the way a buyer should meet it. Your plugin installed and licensed, the settings that make the case switched on, and content that is not Hello World.

Then freeze that as a Template, which captures the WordPress and PHP versions, plugins, theme, files, settings and database as one snapshot.

Every visitor who clicks your launch link gets a fresh copy built from that snapshot and is dropped into wp-admin with a one-time login. There are no credentials to leak because nobody types any.

Whatever one visitor breaks, they break in their own container. The next person lands somewhere else entirely, on a site that is a minute old.

Building it

Four steps, and the third is the one this post is about.

1. Stage the source site. Create a sandbox, install your plugin, configure it, add real content. If the demo should show your product against a real site's data, clone an existing site and stage that instead.

2. Save it as a template. Open the sandbox's menu, choose Save as template, name it. The status moves from building to ready, and the source sandbox stays usable while that happens.

3. Turn on the launch link, and leave protection on. In the template's Share a public demo dialog you get a public URL of the form app.sandywp.com/launch/acme-pro-demo. The Protected demo toggle is on by default, and it is what writes DISALLOW_FILE_MODS and DISALLOW_FILE_EDIT into each launched copy's wp-config.php. Visitors still get a real, clickable wp-admin; they just do not get the installer, the uploader or the file editor. Turn it off only if a particular demo genuinely needs a full-powered admin.

Note that the toggle applies to demos launched after you change it. Copies already running keep the settings they were built with.

4. Pick where they land, and how long it lasts. The landing path is a sandbox-local path such as /, /shop/ or /wp-admin/. It must begin with /; a launch link will not redirect to an external URL. Expiry is either a fixed lifetime or an inactivity timeout, so a demo can close itself an hour after the visitor stops clicking rather than at a fixed hour that may cut someone off mid-evaluation.

If your product is on wordpress.org and you want a demo without staging anything, app.sandywp.com/plugins/<your-slug> builds a clean WordPress with that plugin installed and activated. app.sandywp.com/themes/<slug> does the same for a theme. It is a weaker demo than a staged one, because it has no content and no settings, but it takes no setup at all.

Getting the lead out of the demo

A demo that nobody in your company hears about is a nice gesture, not a sales tool.

The launch link can ask for an email before it builds the copy, which is the difference between traffic and a name. Somebody who typed an address to get a WordPress install has shown more intent than anyone who watched your video to the end.

You can also show a consent checkbox with your own wording, up to 500 characters, and choose whether it starts ticked. The visitor can always clear it, and whether they did is recorded with the launch.

Then wire the launch into whatever you already use. Under Account → Webhooks → Demo Launches, SandyWP will POST a signed demo.ready event when the copy is up, and demo.expired when its lease runs out:

{
  "id": "demo_ready_site_123",
  "type": "demo.ready",
  "occurredAt": "2026-08-02T12:00:02.000Z",
  "templateId": "template_123",
  "siteUrl": "https://demo.example.com/site-123",
  "email": "[email protected]",
  "consent": true,
  "status": "ready",
  "source": "template_launch"
}

The email field is null when the link does not collect one. Requests carry an HMAC signature and an idempotency key and are retried, so a CRM or automation step can consume them without inventing its own deduplication.

That is enough to open a deal record on demo.ready and start a follow-up on demo.expired, which is roughly what sales demos needed from a demo site all along.

When a demo site is the wrong tool

A per-visitor demo is a good answer to "let me try it". It is a bad answer to several other things, and pretending otherwise wastes your time and theirs.

It will not prove performance. A demo container is not your prospect's host, and a stopwatch on it measures our infrastructure, not your plugin.

It will not exercise anything tied to a domain. Payment gateways, OAuth callbacks, email deliverability and some licence servers all check the hostname, and a per-visitor demo has a different one every time.

It will not survive being treated as staging. A demo is disposable by design, so nothing a visitor does in one is coming back, and nothing you do in one belongs in production.

And it will not show scale. Five posts of demo content will never surface the query that falls over on a client's 40,000-product catalogue. That is what a clone of the real site is for, and it is a separate job from the demo.

The short version

Give each visitor their own copy, and switch off the installer and the file editor inside it.

The first half is what the existing guides tell you. The second half is what keeps your paid code from being one menu item away from anybody who clicks your demo link.

If you build and ship WordPress products, the same setup covers your other testing too. See what SandyWP does for plugin developers, or start from Templates.