
How to Create a Recurring Subscription Payment Form in WordPress
A one-time payment field covers a single purchase — an event ticket, a deposit, a donation. A membership site, a SaaS-adjacent service, or any recurring-billing business needs something structurally different: a form that creates an actual subscription, not just a payment, so the customer gets charged automatically on a schedule without filling out the form again. Here's how to actually build one, and what to check before assuming your current plugin supports it the way you expect.
What makes a subscription form different from a payment form
A one-time payment field, submitted, creates exactly one charge. A subscription field, submitted, creates a subscription object in the payment gateway (Stripe, in the overwhelming majority of WordPress implementations) — a standing agreement to charge the customer's saved payment method on a recurring schedule until the subscription is canceled or fails permanently. The initial form submission only creates the first charge and the subscription record; every renewal after that happens automatically on Stripe's side, with no further action from your WordPress site required to trigger it.
This distinction matters because it changes what your form plugin actually needs to do: a one-time payment field just needs to confirm a charge succeeded once. A subscription field needs to also listen for ongoing events — a successful renewal, a failed renewal, a cancellation — arriving via webhook potentially weeks or months after the original form submission, and keep its own record of subscription status in sync with what Stripe actually did.
Real-world use cases
Seeing this applied to specific businesses makes the abstract "subscription form" idea concrete:
Membership and community sites. A single monthly or yearly tier granting access to gated content, a private community, or member-only resources — the simplest and most common subscription form pattern, often paired with a role-change automation on successful payment (upgrading the WordPress user to a "member" role that unlocks restricted content).
Online courses and coaching. Either a flat monthly access fee to an evolving content library, or a fixed-length payment plan (e.g., "3 monthly payments of $99" for a course that's otherwise a one-time purchase) — the second pattern uses subscription billing mechanics to structure what's conceptually an installment plan, not an indefinite recurring charge.
Newsletter and content subscriptions. A paid-tier newsletter or publication, often with a free trial period before the first charge, letting a reader sample content before committing — this is one of the clearest cases where native trial-period support on the payment field matters, versus manually tracking trial eligibility outside the payment system.
Retainer-based services. Agencies and consultants billing a fixed monthly retainer can use a subscription form as a lightweight alternative to invoicing software for straightforward, fixed-amount recurring engagements — though highly variable monthly invoicing (different amount every month) is usually a poor fit and better handled by dedicated invoicing tools instead.
Donation subscriptions. Nonprofits increasingly favor recurring monthly donations over one-time gifts, since predictable recurring revenue is easier to plan against — a donation form with a "make this monthly" toggle next to the one-time amount is a common, high-converting pattern specifically because it doesn't force the choice, it offers recurring as an easy upgrade from the default one-time path.
Designing multiple subscription tiers in one form
Most real subscription forms don't offer just one price — they offer a choice (Basic/Pro/Enterprise, or Monthly/Annual). The common implementation pattern: a selection field (radio buttons or a styled tier-picker) that the payment field's price and billing interval are conditionally bound to, so selecting "Pro — $29/mo" configures the payment field to create a subscription against that specific Stripe Price object, while "Basic — $9/mo" configures it against a different one. This is conditional logic applied to a payment field specifically, rather than to a normal input — worth confirming your plugin's conditional logic engine can actually target payment field configuration, not just field visibility, since not every implementation supports this depth.
An annual-vs-monthly toggle on the same tier is a related, extremely common pattern (frequently with a discount for committing annually) — structurally, this is usually implemented as two separate Stripe Prices attached to the same underlying Product, with the toggle switching which Price ID the subscription gets created against.
Step-by-step: building the form
The general pattern is consistent across the WordPress form plugins that support this properly:
- Connect Stripe in the plugin's payment settings (publishable + secret key, test mode first). Recurring billing support is Stripe-specific on most WordPress form plugins — PayPal subscription support exists on some, but is less universally implemented than Stripe's.
- Add a payment field to the form — usually a dedicated field type distinct from a simple one-time payment field, sometimes the same field type with a "recurring" toggle.
- Set the billing interval — monthly, yearly, weekly, or a custom interval, depending on what the plugin exposes.
- Configure the price. This can be a fixed amount (a single subscription tier) or tied to a selection elsewhere in the form (multiple tiers, each mapped to a different Stripe Price object).
- Add a free trial if needed — most implementations let you set a trial period in days before the first charge fires; Stripe handles not billing until the trial ends.
- Test with Stripe's test-mode card numbers —
4242 4242 4242 4242for a successful subscription creation, and specifically test what happens with a subsequent simulated renewal if your testing setup allows it, not just the initial charge. - Set up webhook handling (usually automatic if you're using the plugin's own Stripe integration rather than a custom build) so subscription status changes — renewal, failure, cancellation — get reflected back into your WordPress entries, not just captured once at creation and never updated again.

When a subscription form is the wrong tool
Not every recurring relationship should actually be built as a subscription. A few cases where a one-time payment (possibly repeated manually) or a different tool entirely is the better fit:
- Highly variable billing amounts. If the charge genuinely differs every cycle (hours billed, usage-based pricing), a fixed-recurring subscription field is the wrong shape — that's a case for either a custom invoicing tool or a usage-based billing system built specifically for variable charges, not a WordPress form's recurring payment field, which generally assumes a fixed amount per interval.
- Very low volume, high-touch relationships. A handful of retainer clients billed monthly might genuinely be simpler to handle via a recurring invoice sent manually or through basic invoicing software, where the overhead of setting up and maintaining a subscription-form integration isn't worth it below a certain subscriber count.
- Uncertain long-term commitment. If what you're actually selling is closer to "book me for a one-off engagement, possibly repeated" than "ongoing access to something," framing it as a subscription (with the churn-management overhead that implies) may be solving a problem you don't have yet — a simple repeatable one-time payment form is less to build and maintain until volume justifies the subscription infrastructure.
Why subscription status has to stay in sync, not just get set once
This is the part that's easy to underbuild: a subscription doesn't have one final state the way a one-time payment does (succeeded or failed, done). It has a status that can change repeatedly over the subscription's lifetime — active, then past_due during a failed-renewal retry window, then either back to active (retry succeeded) or canceled/unpaid (every retry failed). A form plugin's subscription handling needs to listen for Stripe's webhook events for all of these transitions and update its own record accordingly, distinguishing a subscription that's actively failing payment from one that was deliberately canceled — these look identical if you only check "is it still active" without tracking the actual status history.
A plugin that only records "subscription created" at the moment of the original form submission, with no ongoing sync, will show a subscriber as permanently active in its own records even after Stripe has stopped billing them for months — a real, common failure mode worth specifically checking for before relying on a plugin's subscription reporting.
How this compares across WordPress form plugins
Recurring payment support isn't universal, and where it sits in a plugin's tier structure varies:
- WPForms supports recurring subscriptions on any paid license level (not the free Lite plan), with a configurable billing interval from daily up to yearly.
- Gravity Forms, paired with its Stripe Add-On, supports recurring subscriptions — Gravity Forms has no free tier at all, so this is inherently a paid-plan feature regardless.
- WP Simple Pay is a dedicated Stripe payment plugin (not a general form builder) that supports subscriptions as one of its core features, with its own separate pricing structure from the general-purpose form plugins in this comparison.
- ChargeForms is the exception to the pattern above: Stripe subscriptions are included on the free plan, alongside one-time Stripe and PayPal payments, with $0 platform fee — currently Stripe-only for recurring specifically (PayPal subscription support isn't implemented yet, though the underlying data model was built gateway-agnostic specifically so that can be added without a schema migration later).
The practical takeaway: don't assume "payments: free" on a plugin's marketing page implies subscriptions are included at that same tier — most of the time they aren't, which is exactly the gap that makes it worth checking the specific payment field types available at each license level before committing to a plugin for recurring billing.
Handling declined renewals without losing the subscriber
A card declining on a renewal — expired card, insufficient funds, a bank fraud flag — is routine, not exceptional, and shouldn't be treated as an immediate cancellation. Stripe's own retry logic (Smart Retries) automatically re-attempts a failed renewal on a schedule over several days before marking a subscription as truly failed, which gives a subscriber a real window to update their payment method before losing access. Whether your form plugin surfaces this "past_due, retrying" state distinctly from a hard cancellation in its own reporting is worth checking — treating every declined renewal as an immediate lost customer, when Stripe is still quietly retrying in the background, leads to prematurely revoking access (or panicking) over what's often a temporary, self-resolving payment hiccup.
Common mistakes when building a subscription form
- No trial-then-charge testing. Testing only the immediate-charge path and never actually verifying what happens when a trial period ends and the first real charge fires days or weeks later.
- Hardcoding the price instead of using a Stripe Price object. A price change later (raising a subscription tier's cost) is much easier to manage when the form references a Stripe Price ID that can be updated centrally, rather than a fixed amount duplicated across the form's own configuration.
- No cancellation path for the subscriber. A subscription form focused entirely on signup, with no corresponding "manage my subscription" or cancellation flow, routes every cancellation request to manual support handling — worth building a self-service path (even just a link to Stripe's own customer portal) before launch.
- Ignoring webhook failures. If your webhook endpoint goes down even briefly, Stripe retries delivery, but a form plugin that doesn't handle webhook processing failures gracefully can end up with subscription records that silently drift out of sync with Stripe's actual state.
Reducing involuntary churn (dunning)
"Involuntary churn" — a subscriber who didn't choose to leave, but lost access because a renewal payment failed — is a large, often underestimated share of total subscription churn, and it's worth specifically designing for rather than treating as an edge case:
- Rely on Stripe's built-in retry schedule rather than immediately canceling on the first failed renewal attempt — a single declined card is frequently a temporary issue (insufficient funds that resolve by payday, a bank's fraud flag that clears), not evidence the subscriber wants to leave.
- Send a distinct "payment failed, update your card" notification, separate from a generic cancellation email, at the point a renewal first fails — most subscribers who see this promptly update their card before the retry window closes, especially if the email link goes directly to a card-update page rather than requiring them to log in and hunt for it.
- Use Stripe's own hosted customer portal (or an equivalent) for card updates and cancellations rather than building a custom flow — it's a maintained, PCI-compliant surface that handles the update-card-and-retry-the-failed-invoice flow correctly without your form plugin needing to implement that logic itself.
- Track "past_due" as a distinct state in your own reporting, not collapsed into either "active" or "canceled" — a subscriber stuck in extended past_due status is a specific, actionable list (send them a reminder) that's invisible if your system only tracks a binary active/inactive flag.
Tracking MRR from form-created subscriptions
Once subscriptions are live, Monthly Recurring Revenue (MRR) — total predictable monthly revenue across all active subscriptions, normalized to a monthly figure even for annual plans — becomes the key metric worth tracking, and it's worth deciding upfront where that tracking actually happens. Stripe's own dashboard calculates MRR automatically across everything it processes, independent of which WordPress plugin created the subscription, which makes it a reliable source of truth even if your form plugin's own reporting is more limited. If you need MRR broken down by which form or tier generated it (worth knowing which subscription tier is actually driving growth), that typically requires either your form plugin's own segmented reporting or exporting subscription metadata and cross-referencing it against Stripe's data externally — confirm which of these your specific plugin actually supports before assuming per-tier MRR reporting is available out of the box.
Testing checklist before launch
Beyond the basic "does a subscription get created" check:
- Complete a full test-mode subscription creation, confirm the entry and any role/access changes fire correctly.
- If offering a trial, advance to (or simulate) the trial's end and confirm the first real charge fires and is recorded correctly, not just the trial-start event.
- Simulate a declined renewal (Stripe's test mode supports specific card numbers for this) and confirm your system reflects "past_due," not silently keeping the subscriber marked active or immediately canceling them.
- Test the cancellation path end-to-end — both a subscriber-initiated cancellation (via a customer portal, if offered) and an admin-initiated one, confirming both correctly stop future billing and update access.
- Confirm webhook delivery is actually configured and reaching your site — a webhook endpoint that's misconfigured or blocked by a firewall rule will cause silent status drift that's easy to miss until a subscriber complains their canceled subscription is still being billed.
The bottom line
A recurring subscription form is a meaningfully different build than a one-time payment form — not just a checkbox to flip, but a component that has to track state over the subscription's entire lifetime, not just at the moment of submission. Check three things before committing to a plugin for this specifically: whether recurring billing is included at your actual license tier (not assumed from "payments: included" generally), whether the plugin syncs ongoing subscription status via webhooks rather than just recording creation once, and whether a free trial period is supported natively if your pricing model needs one. See the full payments documentation for the technical detail on how ChargeForms handles this specifically, or the pricing page for which tier includes it.
Frequently asked questions
Can I charge a recurring subscription from a WordPress form?
Yes, if your form plugin supports it. The general pattern: a payment field gets set to recurring billing (monthly, yearly, or a custom interval) instead of a one-time charge, and submitting the form creates a real subscription in Stripe (or another supported gateway) rather than a single payment.
Do I need WooCommerce to accept subscription payments on WordPress?
No. WooCommerce Subscriptions is one path, but it's built for a full storefront, not a standalone form. Most dedicated WordPress form plugins with a Stripe integration support recurring billing directly on a payment field, without needing a shopping cart or product catalog at all.
What happens if a subscriber's card is declined on a renewal?
This is handled by Stripe's own subscription and retry logic, not something your WordPress form plugin has to build itself — Stripe automatically retries a failed renewal on a schedule, and the subscription's status changes to reflect it (typically "past_due" during retries, then "canceled" or "unpaid" if every retry fails). Your form plugin needs to listen for Stripe's webhook events to keep its own copy of the subscription status in sync, rather than assuming a subscription stays active forever once created.
Is recurring payment support free on WordPress form plugins?
It varies by plugin, and it's worth checking specifically rather than assuming — payments being available on a free plan doesn't automatically mean recurring billing is included at that tier. On ChargeForms specifically, Stripe subscriptions are included on the free plan alongside one-time Stripe and PayPal payments, with no platform fee on any of it.
Can I offer a free trial before the first charge?
Yes, if the plugin's recurring payment field supports it — this is a standard Stripe subscription feature (a trial period before the first invoice is generated), not something that needs to be built manually. Configure the trial length on the payment field itself; Stripe handles not charging the card until the trial ends.
Related posts



Contact Form 7 Is in Maintenance Mode: What That Actually Means
Contact Form 7's creator confirmed at WordCamp Asia 2026 that version 6.2 is the last feature release — the plugin now gets security patches only. Here's what changes, what doesn't, and what to actually do about it.