PaywallProject plugin

Changelog

Every release, most recent first. Latest: 4.1.0, November 3, 2026.

4.1.0

Latest

New

  • Connect AI assistants over MCP. Set it up in one click (it installs the MCP Adapter, connects, copies the config and tests it), then let Claude or another assistant look up and manage subscribers, subscriptions, levels, coupons, groups, gifts, post access, settings and emails, with a write limit and an audit log of every change.
  • Refund a Stripe charge from the transaction page, in full or in part, with a required reason and a preview of the amount before it goes through.
  • Staff can cancel, resume and reactivate a reader’s subscription from wp-admin. A plan change, made on the reader’s account page or through MCP, now charges exactly the price shown in its preview. Partial refunds now show as partially refunded.
  • Abandoned-checkout reminders. Readers who leave checkout, even before an account exists, get reminder emails that can each carry their own coupon and a secure link back to their checkout. A reader is only reminded when Stripe shows they never paid.
  • Protect e-edition PDFs and dFlip flipbooks behind the paywall, or protect a single PDF from the media library. Refused readers see an on-brand access page whose wording, links and cover you can edit.
  • A level can limit gift articles to some categories, or to all categories except some.

Improved

  • Reconcile with Stripe now also fixes subscribers whose Stripe subscription has ended, pages through large Stripe accounts and skips lifetime levels.
  • On the default and hosted checkout layouts, a reader who enters an existing account’s email now gets a sign-in step right under the email field, as the stepped layout already did. A sign-in link is emailed only when the reader asks for one, and sign-in attempts are throttled.
  • The abandoned-checkout notice is hidden by default, with a setting to show it.
  • The email editor says who gets each template, and when.
  • New wordpress.org banner.

4.0.1

Fixed

  • The Newsletter Glue “Sync all subscribers” button in Tools no longer crashes.

Security

  • Hardened the 3-D Secure checkout finalization.
  • Hardened how REST requests from logged-in members are authenticated.
  • Removed the endpoint that revealed whether an email address has an account, and finishing a free signup now requires the verified one-time code.
  • Every public route, admin form and database query is now checked, sanitized, prepared and escaped, following the WordPress.org plugin review.

4.0.0

Breaking

  • The PPACCESS_MANAGED_INSTALL constant and the ppaccess_managed_install and ppaccess_offer_own_stripe_keys filters were removed. Payments now go through Connect with Stripe only. Sites already charging with stored keys keep working.

New

  • AI Shield — a new Settings → AI Shield tab, off by default, adds robots.txt rules that turn away AI training crawlers and AI search fetchers while Google, Bing and other search engines keep indexing. Pick the bots one by one, and copy a ready-made Cloudflare WAF rule for pages a CDN cache serves before WordPress sees them. The tab warns when a physical robots.txt file or an SEO plugin’s rules still let a blocked crawler in.
  • Newsletter Glue integration — keep a Newsletter Glue list in step with your subscribers, with their status, access, plan and expiry date as custom fields and ready-made “has access” / “no access” segments. It never unsubscribes anyone, and a Tools card backfills existing subscribers. Readers can also join and leave your newsletters and topics from a new Newsletters card in My Account. Off until you enable it.
  • Coupons can now discount recurring payments — choose the first payment only, a number of months, or every payment. Existing coupons keep discounting the first payment only, and editing a coupon now applies to the next checkout or plan change.
  • A subscriber.plan_changed webhook is sent when a subscriber upgrades or downgrades — from the admin, My Account or Stripe — carrying both plans.
  • Subscribers can upload, change or remove a profile photo on the My Account page. It becomes their avatar across the site.

Improved

  • Free plans now use the site’s checkout layout, including the standalone checkout, and email domains restrict free plans as well as paid ones. Each restricted plan can say who it is for, such as “Free for Meeker School District staff”.
  • A post that names a free level can now turn off the free sign-up form on its paywall and show the plans instead. Subscribers on the free level still read it.
  • The own-key Stripe fields, the webhook setup button and the managed-install mode are gone from Settings; Connect with Stripe is the one way to take payments.
  • Ready for WordPress.org: the text domain is now paywallproject, the “Secure checkout powered by Stripe” line is removed, and readme.txt lists every external service the plugin contacts. Tested up to WordPress 7.1.

Fixed

  • A subscriber who bought the plan they already held was charged again for the same period. Checkout now refuses it.
  • A Stripe key saved in the wrong mode — a live key in the test slot, for example — is now refused, so a site set to test mode can never charge a real card.
  • Checkout failed for a recurring pay-what-you-want level that had no Stripe product.
  • The coupon field on the stepped checkout no longer sits flush against the fields above it.

Security

  • Content inside the gating shortcodes is now sanitized, paywall container selectors are validated before they reach CSS, and request input, cookies and inline scripts are sanitized and escaped throughout.

3.1.0

New

  • Free access for listed email domains — a subscription level can now name the email domains it is free to, so everyone at a university, employer or association gets the paid plan at no charge without a coupon each. The address must be verified by one-time code first, and the grant applies only while a new account is being created, so it can never cancel an existing paid subscription. Levels with no domains listed are unchanged: readers see the same checkout as before.

Improved

  • Connecting Stripe now connects a live account by default, with a secondary button for a test account, and the site moves onto the mode it connected — so a new publisher no longer lands on “Stripe is not configured” straight after connecting. A publisher already selling live who tries a test account keeps their working checkout.
  • The free article meter now defaults to one article instead of five, so readers see a sample of the writing and are asked for an email address sooner. Sites that already saved a meter value are unaffected.

Fixed

  • The “Set Up Webhook” button no longer appears on sites that have no Stripe keys to use it — connecting handles webhooks anyway.
  • Changing the email address on the checkout now clears a free-access offer raised for the previous address, so the code and the new account always go to the address on screen.

3.0.0

New

  • Connect with Stripe — connect the Stripe account you already have in one click, with no API keys to paste and no webhooks to configure. Renewals, cancellations and failed payments keep working on their own, and your customers, payouts and Stripe dashboard stay yours. The platform fee is stated on the button before you agree to it, and nothing is offered if it cannot be retrieved. Sites that already take payments with their own Stripe keys keep working exactly as before and are not asked to switch.
  • New setup wizard — six steps (payments, plan, pages, access, checkout, signup protection) that leave a site able to sell. It creates the five pages the paywall needs with their shortcodes, turns on IP metering, applies the recommended checkout, and sets up captcha. Every step can be skipped, and each skip says plainly what it costs. Setup now has its own menu entry, and a notice on PaywallProject screens lists anything still outstanding with a link to the step that fixes it. Running a step again never duplicates a page or a plan, and never overwrites the restriction rules you already have.

Improved

  • Monthly renewals now appear in a subscriber’s status history as “Renewed”, once per paid invoice. Zapier, analytics and emails are not sent anything extra.

Fixed

  • Clearing a subscriber’s Expires date in the admin now makes them never expire, instead of silently keeping the old date.

Security

  • Stripe webhooks with a signature older than five minutes are now refused, so a captured webhook cannot be replayed to grant access again. Several signatures are accepted while a signing secret is being rotated. A server clock more than five minutes out will reject webhooks; this is logged as stripe.webhook.signature_stale, separately from an invalid signature, and the window can be adjusted with the ppaccess_webhook_signature_tolerance filter.
  • Uninstalling the plugin revokes the Stripe Connect credentials before removing them.

2.2.0

New

  • Reconcile Stripe payments — a Tools report that compares every live Stripe subscription against the expiry date held on the site, so a renewal that never applied is visible instead of silent. Download the CSV of the subscribers that have drifted, then repair their expiry dates from Stripe in one click. The report writes nothing, the repair only moves an expiry forward and never changes a status, and both stay hidden until you enable them under Settings → Advanced.
  • Backfill groups — turning on “Group accounts” for a level no longer leaves the subscribers already on it without a group. Preview the count, the seat size and who is affected, then create the groups. Saving a level that newly enables group accounts takes you straight to the form with the level chosen.

Improved

  • Webhook events are now a checklist with a line saying when each one fires, instead of a free-text box where a typo produced a webhook that never fired. Tick “All events” to subscribe to everything; an event added by hand or by a filter is kept and shown as its own row.
  • Every webhook has its own “Save and send test” button and event picker, including the one you are adding, so you can check a single endpoint works rather than firing at all of them at once.
  • The settings page warns before you leave a tab with unsaved changes, and now puts the stored values back after a browser refills the form on reload — so what is on screen is what is saved.
  • “Change plan” now appears for subscribers on a one-time plan, which previously had no route from the account page to the plans.
  • The subscriber.created webhook is now sent when someone actually becomes a subscriber, not when they start checkout, so a reader who abandoned payment is no longer sent to your mailing list. It also carries status, expiry, shipping and phone, as does subscriber.status_changed. Existing fields are unchanged.

Fixed

  • A hosted-checkout subscriber was given an expiry of the next day — the payment link’s lifetime, not their billing period. The expiry now comes from the subscription itself, and one-time purchases get their own correct date.
  • Another plugin’s failing database query inside a webhook — a mail logger, for example — was read as the site’s database being down, so every hosted-checkout signup returned an error and Stripe retried it forever. A failure is now attributed to the query that caused it.
  • On newer Stripe API versions the billing period is stored on the subscription item rather than the subscription, so renewals recorded the payment but left the expiry date in the past, with no error anywhere. It is now read from either place, everywhere the plugin needs it.

2.1.0

1 new, 1 improved, 4 fixed

New

  • WooCommerce integration — sell access through WooCommerce by mapping products and variations to levels on the level screen. One-time orders grant access on payment, and WooCommerce Subscriptions orders renew, cancel and expire it in step with the subscription. Guest checkout creates the customer account it needs, purchases appear in My Account, and the Paywall Project welcome email can be switched off per level so only the WooCommerce emails go out. Off until you enable it under Settings.

Improved

  • The “Admin: new subscriber” notification can be limited to chosen levels, so a free tier no longer buries the paid signups you want to see. Leave the list empty to be told about every level, as before.

Fixed

  • A WooCommerce Subscriptions renewal stored an expiry one billing cycle in the past, so a subscriber who had just paid could lose access days later. The expiry is now read after WooCommerce sets the new payment date, and a wrong date corrects itself on the next paid transition.
  • WooCommerce access is now tied to the order’s real recipient, so a replayed or older order can no longer overwrite a newer purchase.
  • A subscriber with a failing card who joined a group kept their personal Stripe subscription, which carried on retrying the open invoice. Joining a group now cancels a past-due subscription as well as an active one, and the open invoice is voided with it. Group owners are still left alone, since their subscription funds the group.
  • If the Stripe customer behind a subscriber had been deleted in Stripe, checkout and the billing portal both failed with a generic error and only an administrator could clear it by hand. The dead record is now replaced automatically during the same request, so the reader can subscribe or update their card without help.

2.0.0

8 new, 5 improved, 1 fixed, 3 security

New

  • Gift article links — subscribers can share a single article with someone who doesn’t subscribe. One link, one reader, once: the first person to open it claims it, it stops working for anyone else, and it expires. Enable per level with a monthly allowance, adjustable per subscriber; gift activity is reported on the Dashboard and Analytics, with a CSV export of individual links, senders and recipients.
  • Per-subscriber RSS feed — active subscribers get a personal, authenticated feed link from My Account that carries full article content, listing only the posts their own plan grants. The link can be regenerated at any time, which immediately invalidates the old one. Off by default — enable it under Settings → Advanced.
  • Analytics page replaces Insights, with the Dashboard’s reports over a date range you choose. The old ppaccess-insights URL redirects to ppaccess-analytics with the query string intact.
  • Warm leads and missed payments worklists — who to chase before they subscribe, and who to chase before they churn. Missed payments shows the amount, the failure reason, and how long Stripe will keep retrying; both export to CSV.
  • Going quiet — paying subscribers who have stopped showing up, so you can reach them before they cancel rather than after.
  • Reading history — a dated record of the articles each subscriber opened, built for chargeback evidence when a card issuer asks a publisher to show the subscription was actually used. Off by default under Settings → Advanced, kept for 180 days, exportable per subscriber or across a date range.
  • Failed payments are now recorded rather than only reflected in a subscriber’s live status, so missed revenue can be reported on after the fact.
  • Admins can change a subscriber’s email address from the subscriber detail page, and the linked Stripe customer is updated with it.

Improved

  • The paywall display report now says why the paywall appeared and names the free-registration prompt separately from a subscribe prompt, which on a site leading with free registration was previously almost every row.
  • Paywalls rendered on the server are now counted. Only paywalls drawn by the browser were recorded before, which meant reports undercounted signed-in readers specifically.
  • Dashboard and Analytics charts and cards restyled — muted palette, revenue and signups drawn in one frame on two scales, and reports laid out in two columns.
  • Reader links throughout the reports now open the subscriber record rather than the WordPress user editor.
  • A subscription status re-asserted as the same value no longer appends a history entry, which previously grew a subscriber’s meta on every Stripe webhook.

Fixed

  • “Resume” is no longer offered to a subscriber whose Stripe subscription has already finished cancelling, where it always failed; they are offered “Start new subscription” instead.

Security

  • Search-engine crawler verification no longer blocks a PHP worker. Confirming a crawler needs a DNS lookup, and the previous lookup could not be timed out — measured at 16 seconds against an unresponsive resolver. Since anyone can claim to be Googlebot, a burst of forged requests could exhaust the worker pool. Lookups are now bounded and cached per address.
  • Values in CSV exports that begin with =, +, - or @ are neutralised, so a subscriber cannot get a formula to run in a spreadsheet by putting one in a name or email field.
  • Reading history is registered with WordPress’s personal-data export and erase tools, so a subject-access or erasure request can be answered completely.

1.4.5

1 new, 2 fixed

New

  • New ppaccess_captcha_bypass filter to bypass the captcha on specific requests, e.g. the PP Mobile app.

Fixed

  • Subscription cancellations now void any leftover payable invoices for that subscription, so a customer can’t pay an old invoice after their access has already ended.
  • Duplicate subscription-payment transactions caused by invoice and PaymentIntent both recording the same payment.

1.4.4

5 new, 4 improved, 1 fixed

New

  • Configurable multi-day renewal reminders — set multiple “days before expiry” milestones (e.g. 30, 14, 1) on the renewal_reminder email template, with a new {days_remaining} merge tag; each subscriber gets one reminder per milestone as it’s crossed, and reminders reset on renewal.
  • Attach a subscription to an existing WordPress account from Create Subscriber — an email that already belongs to a plain WP user with no paywall metadata can now be turned into a subscriber instead of hard-erroring.
  • Level, status, and expiry-range filters on the Tools subscriber CSV export, in addition to the existing level preset.
  • group.member_access_changed webhook — fires per member when a group owner’s status changes or a member is removed, so downstream automations (Pabbly, newsletter lists) can react to lost or regained access.
  • Remove saved webhooks from the Webhooks settings tab, with an undoable “Remove webhook” action before saving.

Improved

  • Group members now get correct access on capped (metered) levels and on paywalls restricted to specific levels — previously they were blocked or given no group access at all.
  • A free-level member’s personal access is cleared when they join a group, so group-level access applies instead of the free tier.
  • The self-hosted updater now passes the plugin icon through to WordPress so it shows correctly on the Updates screen instead of the default icon.
  • The Leaky Paywall importer on the Tools page is now hidden by default, with a new “Leaky Paywall migrator” toggle under Settings → Advanced to show it while migrating.

Fixed

  • The lead-in fade’s pull-up margin no longer gets zeroed by block-theme global styles, so the paywall card consistently tucks into the fade.

1.4.3

1 fixed

Fixed

  • The paywall card’s top border is no longer hidden by the lead-in fade gradient, and block themes (e.g. Blocksy) no longer add a gap between the fade and the card.

1.4.2

3 new, 1 improved, 1 fixed

New

  • Blocked email domains for free registration — list domains under Paywall → Free registration to stop those addresses from completing a free sign-up; blocked readers can still subscribe to a paid plan, and subdomains of a blocked domain are covered too.
  • Saved level-filter presets — save the Subscribers list level selection as a named preset shared with all admins, apply or delete presets from the level dropdown, and export just a preset’s subscribers from the Tools CSV download.
  • Email me a sign-in link on free registration — returning readers who forgot their password can request a passwordless sign-in link (30-minute, single-use) from the sign-in step, and it works even when requested on one device and opened on another.

Improved

  • The lead-in fade now also appears on server-rendered paywalls — logged-in metered or capped readers see the same fade-out into the upgrade box as anonymous readers — and the paywall card tucks into the fade without a gap.

Fixed

  • Stripe webhooks are no longer lost during a database outage — if a query fails while handling an event, the plugin now returns a retryable error so Stripe redelivers it once the database recovers, instead of silently acknowledging it.

1.4.1

3 new, 1 improved

New

  • Change plan from the account page — subscribers on an active recurring paid plan get a “Change plan” action on [ppaccess_account], and the subscribe page grid now marks their current plan.
  • Per-category paywall copy — override the heading and subheading of the free-registration and subscribe boxes for specific categories, with add/remove rows on the Paywall settings page and a category preview dropdown; when a post has several categories the primary category wins.
  • Free window — optionally keep rule-restricted posts free for a set number of days after publish (Restrictions → Lead-in and bypass), then gate them normally; posts explicitly set to require access still gate immediately, and no metered view is spent during the window.

Improved

  • The Subscribers list level filter is now a checkbox dropdown so you can filter by several levels at once — for example all print tiers together; old single-level filter links keep working.

1.4.0

4 new, 5 improved, 6 fixed, 1 security

New

  • Subscriber-only commenting — a new comment gate restricts who can post comments to active subscribers, optionally limited to specific levels, with configurable logged-out and upgrade messages. Enable it under Restrictions → Comments; comment moderators can always post.
  • Lapsed-subscriber access — optionally let past-due, canceled, or expired members who were on a paid plan keep the access of a chosen free level instead of being blocked. It only grants access, leaves their status and level untouched, and is fully reversible.
  • Passwordless sign-in recovery at checkout — a returning subscriber who forgot their password can request an emailed sign-in link that returns them straight to the checkout they were on, logged in at the payment step.
  • Gift redemption now collects a shipping address when the gifted level ships something — pre-filled for signed-in recipients, marked required when the level requires it, and validated before the recipient account is created.

Improved

  • Direct free sign-up forms now honor the level’s configured fields (name, phone, company, billing, shipping) instead of only first/last/email, so free print and mailing tiers can collect a shipping address; the flow no longer redirects back to the subscribe page and saves profile fields before activation.
  • Custom email templates now accept full HTML — paste a complete responsive email with <!DOCTYPE>, <head>, and <style> (media queries, !important) and it is stored intact instead of being stripped and dumped out as visible CSS. Applies to the global and per-level templates for editors with the unfiltered-HTML capability.
  • Metered articles now render inline for logged-in readers, so embeds, maps, and inline scripts inside gated content load correctly — no more stuck loading skeletons or “x is not defined” errors, and no flash of hidden content before the paywall.
  • The free-registration slide-up prompt has been restyled NYT-style — the article fades to white into the form panel instead of a dark scrim, with a subscription-options callout, an “or” divider, larger inputs, full style-preset support, and a fix for the panel getting stuck when dragged down on mobile.
  • Accepting a group invitation now cancels the member’s own personal subscription so they aren’t billed twice, and fires the subscriber.created webhook so invited members reach your integrations.

Fixed

  • Subscription payments no longer record a duplicate transaction row — Stripe’s 2025 API moved the payment-intent field the dedup relied on, and the webhook now reads it from the new location.
  • Recurring-level subscribers with no Stripe subscription — manually created, imported, check-payment, or complimentary — now expire on schedule instead of staying active forever.
  • A canceled subscriber is no longer reverted to past_due by Stripe webhooks.
  • Custom transactional email templates no longer send the welcome email twice.
  • Checkout no longer fails with an opaque “502 Could not create Stripe customer” when a shipping address is entered without a name — first/last name is now required alongside shipping, and Stripe’s real error message is surfaced.
  • Form inputs no longer trigger iOS Safari’s zoom-on-focus on mobile.

Security

  • Hardened group-invitation acceptance against emailed-link replay (each link is now single-use) and against a member cancelling or orphaning a group they already own.

1.3.0

4 new, 5 improved, 2 fixed, 1 security

New

  • Pay-what-you-want levels — a new “Pay what you want” payment type lets buyers enter their own amount at checkout, with configurable minimum, maximum, and suggested defaults, billed either one-time (a donation) or on a recurring interval. Works for new signups and plan changes, with the server always re-clamping the entered amount authoritatively.
  • Admin email notifications for three new conditions — payment succeeded, subscription canceled, and subscription expired — each an individually toggleable, editable template under PaywallProject → Emails. The expired notice can be scheduled a set number of days before or after the expiry date.
  • Search subscribers by name — the Subscribers list search now matches first, last, and display name (not just email and IDs), auto-submits as you type, and a new quick-jump autocomplete on the subscriber detail page links straight to any other subscriber.
  • Per-level CTA button label — override the subscribe grid button text for each level, defaulting to “Subscribe” when left blank.

Improved

  • Customer merge tags ({phone}, {shipping_address}, {billing_address}) now work in every email template, not just admin notifications, and are filled in automatically from the subscriber.
  • The email template picker is grouped into labelled sections — Subscriber emails, Admin notifications, Gift emails, and Group accounts — for easier scanning.
  • The {admin_url} email merge tag has been renamed to {subscriber_url} for clarity; {admin_url} keeps working as a backward-compatible alias.
  • The default renewal reminder email copy has been rewritten for manual (non-recurring) renewals — an accurate “this plan doesn’t renew automatically” message with a manage-account link and a proper greeting.
  • Pay-what-you-want level cards now show a “From” price (or “Pay what you want” when no suggested amount is set) instead of $0.00, and the checkout amount field snaps to the enforced minimum or maximum on entry.

Fixed

  • Pay-what-you-want (donation) levels are now exempt from Stripe Tax by default — a donation has no fixed taxable price and was blocking checkout with a tax-address error; a new ppaccess_level_taxable filter lets publishers re-enable tax per level.
  • The cancel-and-recheckout notice no longer always reads “trial” — it now reflects whether the current subscription is a trial or an active plan.

Security

  • Group-member invite keys are now generated with a cryptographically secure random generator instead of a predictable value.

1.2.0

10 new, 8 improved, 1 fixed

New

  • New [ppaccess_login] shortcode — a standalone login form styled like the account page, with a smart post-login redirect back to where the visitor came from.
  • New [ppaccess_members_only] shortcode — wraps content so it is visible only to active subscribers.
  • New [ppaccess_guests_only] shortcode — hides the wrapped content from logged-in users.
  • Account page now offers a self-service password change in the profile form and a full forgot-password reset flow.
  • Account shortcode now renders nested shortcodes inside its content.
  • Admin transaction detail page — inspect a single transaction with a paid/free status split and the subscriber’s billing address.
  • Per-level welcome email — each subscription level can define its own welcome email subject and body, falling back to the global template.
  • Tag-based paywall bypass — posts carrying selected tags always bypass restrictions, configured with a searchable tag picker in the Restrictions admin (mirrors the existing bypass-by-category).
  • Subscribers are now logged in automatically after completing Stripe hosted checkout.
  • Plan descriptions are parsed into paragraphs and bulleted feature lists for richer plan display.

Improved

  • The inline paywall now renders server-side when the access decision is final, removing the brief client-side flash; the free-registration slide-up continues to work on the JavaScript path.
  • Free, Subscribe, and Upgrade paywall box copy now allows HTML, and the heading/subhead render on both card templates with newlines converted to line breaks.
  • Paywall lead-in length is now measured by word count instead of HTML element count, for more consistent truncation.
  • Leaky Paywall migrator now batches transactions, migrates group accounts, and retries on failure for more reliable large imports.
  • Slack notifications now show the subscription level name instead of the numeric level ID.
  • The paywall “Log in here” link now points at the configured [ppaccess_login] page.
  • Levels admin table now displays each level’s ID for use in shortcode level attributes.
  • Inline checkout is limited to card payments for more reliable processing, and the “send a magic link” fallback was removed from the paywall OTP sign-in flow.

Fixed

  • Renewal reminder emails are now sent only to non-recurring subscribers — recurring subscriptions renew automatically and were receiving reminders they did not need.

1.1.0

1 improved, 6 fixed

Improved

  • Stripe Tax invalid-address error now returns a clear “check your ZIP/postal code” message at checkout instead of the generic subscription failure; card postal code is forwarded server-side and used as a tax location fallback for card-only levels.

Fixed

  • Free registration box settings (heading, subhead, CTA label/URL, show login) not persisting on save — fields were never registered in SettingsDescriptors so values were silently discarded.
  • Expiration cron wrongly expiring never-expire accounts — empty/0 expiry values were cast to 0 by MySQL and matched the expires < now query; a lower-bound guard and a PHP safety check now skip those accounts.
  • Subscriber bulk delete silently doing nothing for non-Stripe subscribers; per-row Delete action added to the subscribers table.
  • Subscriber delete now removes all _ppaccess_* meta from the WP user instead of deleting the WP account; delete actions are blocked for subscribers with an active Stripe subscription.
  • Incorrect proration amount shown when switching across billing intervals (e.g. yearly → monthly) with a coupon — prorated charge is now read from Stripe’s invoice-preview line items instead of being recalculated from the old plan’s period.
  • Surcharge price cache key omitted billing interval, causing stale surcharge prices after an interval change and Stripe rejections on plan updates.

1.0.0

36 new, 10 improved, 21 fixed, 1 security

New

  • Stripe Payment Element as an optional alternative to the classic card element.
  • Stripe Tax support for recurring and one-time subscriptions.
  • Stripe Address Element for tax estimation at checkout.
  • One-click Stripe webhook setup from Settings → Stripe tab.
  • Group Accounts — owners can invite members, manage seats, and switch plans with automatic group resizing.
  • Gift subscriptions — purchase and redeem gift access codes.
  • Coupon support with ppaccess_coupon URL param, lifecycle fixes, and proration accuracy improvements.
  • Plan-change preview showing prorated amount due before confirming a switch.
  • Terms of Service banner and checkbox on checkout, configurable per level.
  • Per-level shipping surcharge based on subscriber postal code.
  • Stripe Tax applied to shipping surcharges.
  • Bypass paywall by post category, with category filter UI in Restrictions admin.
  • Per-post lead-in override — set the number of visible paragraphs before the paywall on individual posts.
  • Slide-up free registration form with server-side content truncation.
  • IP exception management with delete functionality.
  • Option to hide a level from the subscription/levels page.
  • Drag-to-reorder levels with visual level cards.
  • Option to disable the direct sign-up link per level.
  • Custom color controls for paywall boxes.
  • Self-hosted plugin updater — receives updates from paywallproject.com without the WordPress.org directory.
  • Leaky Paywall migrator — import subscribers, levels, and shipping metadata with per-user dry-run details.
  • Subscriber CSV export and import, including phone number field.
  • Phone number display and editing on the admin subscriber detail page.
  • Admin can create a new Stripe subscription from the subscriber detail page.
  • Admin Stripe sync — syncs active/canceled status, expiry date, and shipping address to Stripe.
  • Admin email notifications on plan switch for all subscription types.
  • Support for multiple admin notification email addresses.
  • {shipping_address} merge tag for admin new-subscriber email notifications.
  • Renewal reminder emails with deduplication via cron.
  • Subscriber webhooks include first_name, last_name, and level_id in all payloads.
  • ppaccess_subscriber_created webhook fires on free registration.
  • charge.refunded included in webhook setup event list.
  • Daily database pruner for logs and tightened Insights date range.
  • Interactive admin charts with tooltips, legends, and improved accessibility.
  • Cancel subscription confirmation modal on My Account page.
  • Loading spinner on checkout buttons to prevent double-submit.

Improved

  • My Account page redesigned with card-based layout.
  • Levels admin page redesigned with sectioned layout.
  • Checkout and level admin pages use consistent ppaccess-form-row layout with live checkout preview.
  • Group Accounts admin page uses ppaccess-card styling; Subscribers table columns reordered (email before name).
  • Restrictions admin page gains category filter input and grid layout for bypass sections.
  • Mobile styling improvements for admin area.
  • PaywallProject menu moved to the bottom of the WP admin sidebar.
  • pending_cancel subscriptions no longer show a cancel link; a status note is shown instead.
  • Plan-change banner skipped when amount_due is zero or negative.
  • Same-plan checkout skips proration and applies coupon without re-billing.

Fixed

  • Payment Element blank fields in stepped checkout.
  • Payment Element blank for logged-in users.
  • setup_intent_already_succeeded blocking Payment Element checkout.
  • Potential double-charge for one-time levels with Payment Element.
  • Tax estimate falling back to shipping address correctly with Payment Element.
  • Plan-change proration preview coupon accuracy.
  • Plan-change preview returning 502 for discounted subscriptions.
  • fresh_checkout returned (200) instead of 400 for subscribers without a Stripe subscription on plan-change preview.
  • Double public/ in nonce URL from restriction resolver.
  • Checkout token consumed by coupon check before subscribe submit.
  • Cron jobs not firing and renewal reminder deduplication.
  • push_update TypeError when transient is not an object.
  • Group membership ended message shown correctly even when a subscriber record exists.
  • Fatal error in add_member when first name is empty and user lookup fails.
  • Blank account page for group owners without a subscriber record.
  • Blank page on Add Member — redirect always runs after nonce validates.
  • Preserve subscription status when expiration date is unchanged in admin save.
  • Level ID synced via webhook metadata and update_subscription_price.
  • UTF-8 mangling in lead-in content and Leaky Paywall migrator gateway detection.
  • Lead-in override of 0 now correctly shows no content before the paywall.
  • Leaky Paywall migration no longer overwrites PaywallProject paywall messaging and settings.

Security

  • Fail-closed webhook secret validation — unsigned events are now rejected instead of processed.

0.1.0

The first internal builds, before the public 1.0.0 release.

Want these updates without lifting a finger?

On a managed plan we install every release for you.