The Bench

Screenshot of the bench demo homepage

A fictional paid online community — The Bench — for furniture makers and hand-tool woodworkers. Sixth demo on the platform, and the first that demonstrates WordPress for the membership / gated content / paid newsletter / knowledge-base request that coaches, course creators, and SaaS-adjacent clients all hit. Stack is the free Paid Member Subscriptions plugin plus a thin per-demo theme plus a 70-line mu-plugin that handles the paywall card and the asset-dequeue. Live at bench.wp.philiprehberger.com.

The challenge

Paid community sites — substacks-with-extras, gated knowledge bases, niche professional groups — have become one of the most common questions a freelance developer gets. The asker is almost always weighing four options: Substack, Patreon, Ghost, or Memberful. All four are reasonable defaults; none of them are quite what the asker wants once they describe the actual requirement. Substack and Patreon don’t let you own your URL or your members. Ghost is closer but its membership tier is opinionated about pricing and forms. Memberful is solid but requires either a Memberful-hosted site or a heavy WordPress integration. None of them give you the editorial freedom of a real CMS plus the structural flexibility of a real plugin ecosystem.

WordPress can do this, and has been able to do it for over a decade, but the conversation never gets there because the prevailing freelancer portfolio doesn’t show it. The Bench is the worked example: three membership tiers, category-based content gating, a credible paywall that doesn’t feel cheap, account management, and a writing-first front end that doesn’t apologize for being a CMS.

The approach

The membership plugin chosen was Paid Member Subscriptions (PMS), free on wordpress.org, actively maintained. The original choice was Paid Memberships Pro (PMPro), which has historically been the canonical option in this space — but PMPro’s wordpress.org listing is currently closed, so the install path required the pivot to PMS. PMS turns out to be a clean, well-architected alternative: subscription plans as a CPT, content restriction at the post and taxonomy level, four shortcodes for the standard account flows ([pms-register], [pms-login], [pms-account], [pms-recover-password]), Stripe support built in.

The per-demo theme (bench) is a child of the platform chassis with a walnut + oxidized-brass + oat palette and Spectral serif headings — intentionally different from the four other per-demo themes already on the platform, intentionally consistent with the rest of the chassis machinery (typography scaling, button + card primitives, the gotcha-busting CSS layer).

All membership configuration — the three subscription plans, the four categories, the category-level gating, the four PMS account pages — runs from a single idempotent seed script (.scripts/seed-pages.sh) using wp-cli. The mu-plugin (bench-pms-setup.php) is intentionally small: it only handles two things PMS doesn’t do well out of the box, which are the paywall card’s visual design and the asset-dequeue that protects Lighthouse perf on the marketing pages.

What’s on the site

  • Home. Walnut cover hero with brass eyebrow, Spectral headline (“A library for serious hand-tool woodworkers”), pricing + free-lesson CTAs. Below: four-bullet value proposition and a three-card featured-posts row pulling from the most recent published work
  • /library/. The WordPress posts page (set via page_for_posts), rendered by the theme’s home.html FSE template. Three-column card grid showing every post — including gated ones, so the library can advertise members-only work. The PMS pms_includeRestrictedPosts setting is flipped to yes so restricted posts stay in the loop instead of being silently excluded
  • /workshop/. A free sample page that links straight to “Why we still draw by hand” — a free essay deliberately chosen to demonstrate the format without giving away the lessons-and-projects body of the library
  • /about/. Brokerage philosophy (“why paid”), how the membership works, and the two co-founder bios (Sam, period furniture; Ruth, design and drawing)
  • /pricing/. Three-tier pricing card grid with direct links into PMS’s register form pre-selecting the tier (/register/?subscription_plan=<id>)
  • /register/, /login/, /account/, /recover/. Single-shortcode PMS pages, registered with the plugin’s pms_pages option so its inter-form links target the right URLs
  • 6 posts across 4 categories (Lessons / Essays / Projects / Office Hours): 2 free essays, 3 members-only (Lessons + Projects), 1 founder-only (Office Hours)
  • Single-post template with custom paywall card replacing PMS’s default restricted-content message for both logged-out and logged-in-no-subscription cases

The stack in detail

  • _chassis parent theme — templates, parts, patterns, gotcha-busting CSS, filemtime-based stylesheet enqueue. Inherited from the platform via symlink
  • bench per-demo theme (this repo) — declares Template: _chassis, ships the walnut + brass + oat theme.json and Spectral serif typography, custom parts/header.html (Library / Workshop / About / Pricing / Sign in) and parts/footer.html (community + office + member links), home.html for the library archive, single.html for individual posts
  • Paid Member Subscriptions — third-party WordPress plugin installed via wp plugin install paid-member-subscriptions --activate. Handles user registration, login, subscription tiers (priced at $0, $12/mo, $24/mo), Stripe payment integration, account-management pages, post + taxonomy access control via post_meta + term_meta. Not vendored in this repo — lives in the demo’s own wp-content/plugins/ directory
  • bench-pms-setup.php (demo-local mu-plugin) — two responsibilities: (a) replace PMS’s default restricted-content message with a custom paywall card via the pms_restriction_message_logged_out, pms_restriction_message_non_members, and pms_restricted_term_message filters; (b) dequeue PMS’s front-end CSS + Stripe.js on pages where no PMS form renders, which is the difference between Lighthouse perf 51 and perf 75 on the home page
  • bench-banner-config.php — filters the demo banner copy for membership context
  • WordPress 6.x · PHP 8.3 · MySQL 8 on Apache 2.4 (the same EC2 t3.small that hosts every other demo on the hub)
  • .scripts/seed-pages.sh — idempotent seed that handles everything PMS doesn’t auto-create: three subscription plans (as pms-subscription CPT entries with the right meta), four categories, term_meta-based category gating, six seeded posts with featured images, four PMS account pages, the pms_pages option mapping, the pms_includeRestrictedPosts override, and the front-and-posts-page assignments

Where we made tradeoffs

Picked PMS over PMPro after the install path forced the choice. The original plan was Paid Memberships Pro, which is the canonical default for this work. PMPro’s wordpress.org listing turned out to be closed at the time of build, so wp plugin install paid-memberships-pro fails. The right move could have been to install PMPro from its GitHub releases — perfectly viable, just heavier vendor management for the demo — or to switch plugins. We switched, because the lesson worth demonstrating is that the membership pattern is portable across plugins; the per-demo theme and the paywall card and the asset hygiene all stay the same regardless of which plugin underwrites the auth. The mu-plugin would be ~80% identical for PMPro; the seed’s plan and gating helpers are the only meaningful differences. Documenting this here so a future client conversation about “we want PMPro instead” reads as a small lift, not a rebuild.

Category-level gating over per-post gating. PMS supports both. Per-post is more granular — you can mark a specific post as members-only without committing the whole category. Category-level is structural — “essays are free; lessons + projects are member; office hours is founder” is a rule the site enforces without any per-post editorial overhead. We went with category-level because that’s the model that actually scales for a publication with 60+ posts a year; per-post overrides are still available when an essay wants to be in the lessons category. The cost is one term-meta restriction setup per category; the benefit is that future posts inherit the access policy from their category assignment with zero manual gating per post. Trade reads correctly for a publication; would flip for a course-builder where every lesson is its own gating decision.

Custom paywall card over PMS’s default messaging. PMS ships with a default “You must be logged in to view this content” message that’s functional but visually disconnected from the host site. We replaced it with a styled paywall card via three filter hooks (pms_restriction_message_logged_out, pms_restriction_message_non_members, pms_restricted_term_message). The card includes a credible preview (“Members get the full archive of lessons, essays, and project plans — about 60 pieces and growing weekly”), a CTA to the pricing page, a secondary “Already a member? Sign in” link, and a callout to the free workshop sample. The hard part wasn’t the design — it was discovering that taxonomy-level restrictions use a different filter (pms_restricted_term_message) than post-level restrictions, which is buried in functions-content-restriction.php rather than the plugin’s docs. Documenting that here as gotcha #1 for the next bench-shaped project.

The Lighthouse perf number is honest about PMS’s overhead. PMS loads its frontend CSS and Stripe.js on every pageload by default, which on a marketing home page costs roughly 25 perf points (51 vs 76 in our case). We added an asset-dequeue in the mu-plugin to strip PMS-prefixed enqueues on non-account pages — that recovers most of the lost perf. A real client engagement would either add server-side caching (Redis object cache + page cache via WP Super Cache or similar) to recover further, or accept the 75 perf as the price of having a working membership flow at minimal build complexity. We’re showing perf=75 in the demo because it reflects the genuine starting point a client lands on after install — the optimization conversation is what the engagement adds.

Outcomes

  • Six-page marketing + library site plus four PMS-managed account pages live at bench.wp.philiprehberger.com, end-to-end provisioned via the platform’s provision-demo.sh script plus a one-line wp plugin install paid-member-subscriptions
  • Working three-tier membership flow: Free reader at \$0, Member at \$12/mo, Founder at \$24/mo — with category-level content access controls that route to a custom paywall card for any visitor without a qualifying subscription
  • The shared platform stayed entirely untouched. No new sfp-blocks blocks, no chassis changes, no shared mu-plugin updates — the membership pattern is implementable as pure per-demo work, which is the right answer for any pattern that’s genuinely demo-specific
  • Lighthouse: 75 / 92 / 77 / 92 (perf / a11y / best-practices / SEO). The perf number reflects PMS’s third-party-asset overhead; the best-practices drop is from Stripe.js loading from a third-party origin (correct behavior for a payment integration, flagged by Lighthouse by default)
  • Greenfield-to-live in approximately five hours including the plugin pivot from PMPro to PMS, the per-demo theme, the seed script with three plans + four categories + six posts + four account pages, and this writeup. The pivot cost about thirty minutes of debugging the PMS API surface against the original PMPro setup
  • Establishes a clean reference for the membership / gated-content client conversation: “yes, WordPress, here’s a working example, here are the tradeoffs we accepted, here’s the perf cost and how to recover it.” The demo is the document.

Tagged

Industry:
Builder:
Theme:
Features: ,

Facts

Perf

A11y

SEO

BP

Build time: hours