Skip to main content

Products, licenses, and subscriptions

Watch the walkthrough

Follow the commerce workflow from setup to fulfillment

These short walkthroughs cover store setup, products and plans, catalog blocks, checkout, orders, licenses, and the customer dashboard.

Turn WordPress Into a Digital Product Store with Core Forms Enable the license server and create the shared checkout and customer dashboard pages.
Create Digital Products and Pricing Plans in Core Forms Add a digital product, then configure free and annual plans with separate activation limits.
Build a Product Catalog and Checkout in WordPress with Core Forms Build a catalog with Core Forms blocks, connect a buy button, and preview the completed storefront.
Test a Core Forms Checkout and Manage Orders and Licenses Follow a free checkout through the storefront, admin order, issued license, and customer dashboard.

Watch the complete Core Forms playlist on YouTube →

Core Forms can act as a lightweight digital-product checkout and license server. Payment gateways collect money; Core Forms owns the product catalog, orders, license keys, signed package downloads, customer access, and subscription terms.

Core Commerce 4.7 overview with operational alerts and store totals

Set up the store

  1. Enable Core Commerce → Settings → Store setup → Enable license issuing. Core Forms creates a native Checkout page containing [cf_license_checkout] and a Customer Dashboard page containing [cf_license_dashboard].
  2. Open Core Forms → Core Commerce and add each product. Products may be plugins, themes, or other digital downloads. Add a square Media Library icon when you have one; Core Forms supplies a product-type fallback otherwise.
  3. Add one or more plans per product. A plan defines price, currency, billing period, license duration, trial, and activation limit.
  4. In Settings → Payments → Currency routing, assign each currency to one or more compatible gateways and choose its default. Core Forms starts with USD routed to Stripe, PayPal, and Polar, and INR routed to Razorpay. A configured route is enforced before checkout.
  5. Link customers to /core-checkout/?cf_product=product-slug&cf_plan=plan-slug, or use the product catalog. The native checkout reads the product and plan, shows every configured gateway allowed for that currency, stores the order, and issues the license after free checkout or a verified paid webhook. It does not require a Core Form post.
  6. When a product needs additional fields or actions, open its Forms section and choose Generate optional Core Forms. Core Forms creates a separate editable checkout form and page per active plan, plus a renewal form for renewable products. These sample checkout forms include optional phone, company, tax, billing-address, licensed-site, and order-note fields. Their fulfillment action maps the customer data, sends the license email, and notifies the store administrator. The generated form uses the default gateway from the currency route.
  7. Open the product's Releases section and publish a ZIP from the Media Library. Core Forms checks ZIP integrity, unsafe paths, product headers, declared version, and the SHA-256 digest before making it current.

Generated Core Forms are non-destructive and optional. Running the action again creates only missing forms or pages and never overwrites a form that has been edited. Billing fields are optional starting points and can be removed or made required in the form editor. The catalog always uses the native shared checkout, which asks only for name, email, and consent; generated pages are available for custom campaigns and richer form workflows.

To explore the workflow without building records by hand, open the Products list and choose Generate sample products. The action inserts only missing sample plugin, theme, and digital-download records and plans, so repeated runs do not create duplicates or replace edits.

Payment-enabled forms do not run fulfillment when the browser merely returns from checkout. Core Forms waits for the gateway's verified paid webhook, then atomically runs the action. The action logger and order source key make webhook retries idempotent.

Sell multiple products or bundles

Set Product selection field to a form variable such as [products]. Add one mapping per line:

core-forms=12:4:1
agency-bundle=12:7:1
analytics-addon=18:9:2

The format is submitted-value=product_id:plan_id:quantity. Checkbox or multi-select values may be comma- or pipe-separated. Every selected mapping becomes an order item, and the quantity controls how many separate keys are issued.

You may also add the fulfillment action more than once to a form. Existing saved issue_license actions continue to work.

Customer dashboard and catalog

Use the Customers tab for a case-insensitive buyer view that combines orders, licenses, and active sites. See Customers, orders, and activated sites for the administrative workflow.

  • [cf_license_dashboard] displays orders, full keys with reveal/copy controls, current package downloads, expiry, subscription term, and activated sites.
  • Logged-in customers are matched by WordPress user ID or email.
  • Guest customers receive a signed, 30-day dashboard link. The signature is verified server-side and does not expose a reusable password.
  • Customers who lose that link can request a fresh one from the dashboard page. The form never reveals whether an email is associated with an order and throttles repeated requests.
  • Customers can deactivate individual sites and stop local renewal tracking.
  • [cf_license_products columns="3" type="plugin" limit="6"] renders a filterable product and plan catalog. It also supports orderby="name|created|updated|version" and order="ASC|DESC".
  • [cf_license_product_list type="plugin" limit="8" show_price="1"] renders a compact directory when full pricing cards would be too heavy.
  • [cf_license_product product="core-forms-pro"] renders one product and all active plans. Add plan="personal" to show one plan, or show_description="0" and show_version="0" for a tighter card.
  • [cf_license_price product="core-forms-pro" plan="personal"] outputs only a formatted plan price.
  • [cf_license_buy_button product="core-forms-pro" plan="personal" label="Buy Core Forms"] outputs a direct checkout button.
  • [cf_license_checkout] uses the product and plan URL parameters on the shared checkout page. In a fixed campaign page, [cf_license_checkout product="core-forms-pro" plan="personal"] pins the selection.

Each shortcode has a dynamic Block Editor replacement with product and plan selectors and a server-rendered preview. Editors can find them by searching for “product”, “license”, or “checkout”. The full reference is available under Core Forms → Core Commerce → Display and in the global Core Forms settings screen.

Core Forms does not create a public single-product page for every product. Choose a page and insert the relevant blocks or shortcodes. See Product pages, blocks, and shortcodes for copy-ready examples and a publishing checklist.

Package links expire after 15 minutes. New links use an internal license record ID instead of carrying the full license key. Downloads require an active, unexpired license, verify the stored SHA-256 hash, and are written to the download audit and activity tables.

Renewals and refunds

Use a separate paid form with the Renew License Subscription action. Include license_key and email fields. The dashboard links to this form without pre-filling either secret in its URL. After payment confirmation, Core Forms records a renewal order and extends the existing subscription and key from the later of today or the current period end.

Core Forms tracks recurring terms, access, cancellation, expiry, and renewal orders. The selected payment provider still owns automatic charging and payment-method storage. Connect its successful renewal event to a paid Core Forms renewal submission when automatic recurring collection is required.

A verified refund marks matching orders refunded, disables their issued licenses, and cancels their subscriptions. Daily maintenance expires overdue subscriptions and licenses. Run it manually with:

wp core-forms license maintenance

License client API

EDD Software Licensing-compatible endpoints remain available:

/wp-json/core-forms/v1/check_license
/wp-json/core-forms/v1/activate_license
/wp-json/core-forms/v1/deactivate_license
/wp-json/core-forms/v1/get_version

Send license plus item_id or item_name, and url for site-specific activation. Legacy ?edd_action= requests remain supported.

See Integrate license keys and automatic updates for a complete WordPress plugin client, activation flow, update hooks, fresh signed package downloads, theme notes, and an end-to-end test checklist.

The authenticated/signed customer endpoint is:

GET /wp-json/core-forms/v1/customer/licenses

Cookie-authenticated WordPress requests use the normal REST nonce. Guest requests send the access_token from the dashboard link.

Authenticated commerce REST API

Administrators and integrations with manage_core_forms_licenses can operate the complete commerce workspace under /wp-json/core-forms/v1/commerce. WordPress cookie authentication requires the normal REST nonce; application passwords and other standard authenticated REST transports also work. These endpoints never return payment credentials or full license keys.

Resource Endpoints
Overview GET /summary
Products GET, POST /products; GET, PATCH /products/{id}; POST /products/{id}/generate-forms
Plans GET /plans; GET, POST /products/{product_id}/plans; PATCH /plans/{id}
Releases GET /releases; GET, POST /products/{product_id}/releases
Orders GET /orders; GET /orders/{id}; POST /orders/{id}/resend-access
Licenses GET /licenses; GET, PATCH /licenses/{id}; reset activations and resend access through the record action endpoints
Operations GET /activations, /subscriptions, /downloads, and /events; deactivate one activation or update one subscription by ID
Setup POST /sample-products; GET, PUT /currency-routes; GET /gateways

Products and plans are archived by changing status; this API intentionally provides no destructive delete route. Publishing a release accepts a WordPress Media Library attachment_id, validates the ZIP, and requires replace_existing: true before replacing the same product version. Currency-route updates modify only the routing map and preserve stored gateway credentials.

Public Storefront REST API

Static sites, JavaScript applications, and external sales pages can read the customer-facing catalog without using an administrator credential:

GET /wp-json/core-forms/v1/storefront
GET /wp-json/core-forms/v1/storefront/products
GET /wp-json/core-forms/v1/storefront/products/{slug}

The product collection accepts page, per_page, type, currency, search, orderby, and order. The single-product route accepts an optional three-letter currency filter. Product responses contain only public slugs, names, descriptions, versions, resolved icons, active plans, formatted and minor-unit prices, billing and license terms, and hosted checkout URLs. Database IDs, form and page references, archived records, releases, orders, customer data, license keys, gateway configuration, and credentials are never included.

The public catalog is available only while Settings → License Issuing Server is enabled. Responses support cross-origin reads, five-minute shared caching, ETags, and conditional 304 Not Modified requests. Use cf_storefront_enabled, cf_storefront_cache_ttl, cf_storefront_product, and cf_storefront_plan to control availability, caching, or additional public fields.

Astro can load a product during a static build:

---
const response = await fetch(
  'https://store.example.com/wp-json/core-forms/v1/storefront/products/core-forms-pro'
);
const product = await response.json();
---

<h2>{product.name}</h2>
{product.plans.map((plan) => (
  <a href={plan.checkout_url}>{plan.formatted_price}</a>
))}

Checkout remains on the WordPress store so gateway routing, payment verification, orders, and license fulfillment continue to use the existing secured workflow.

WordPress and MCP abilities

On WordPress 6.9 or newer, Core Forms registers the same operations as discoverable abilities in the core-forms-commerce category. The ability names use the core-forms/ namespace, including list-products, save-product, save-plan, publish-release, list-orders, list-licenses, update-license, generate-product-forms, generate-sample-products, get-currency-routes, update-currency-routes, and get-gateway-status.

Every ability:

  • requires manage_core_forms_licenses or manage_options;
  • declares read-only and idempotency annotations;
  • is exposed through the WordPress Abilities REST controller;
  • sets mcp.public for compatible WordPress MCP adapters;
  • calls the same validated service as the direct commerce REST routes;
  • keeps credentials and full license keys out of tool output.

WordPress 6.4 through 6.8 continue to use the direct REST API. The Abilities registration is conditional and does not change the plugin's minimum WordPress version.

WP-CLI

wp core-forms license product-list
wp core-forms license product-create "Core Forms" --slug=core-forms --version=4.4.2 --activation-limit=3
wp core-forms license plan-list
wp core-forms license order-list
wp core-forms license license-list --limit=1000 --format=csv
wp core-forms license maintenance

Extension hooks

  • cf_license_order_fulfilled( $order_id, $license_ids, $submission, $form )
  • cf_license_renewed( $license_id, $expires_at, $submission, $form )
  • cf_license_order_refunded( $order_ids, $submission )
  • cf_license_maintenance_completed( $subscriptions_expired, $licenses_expired )

Run alongside another store

Core Commerce uses a dedicated /core-checkout/ page. Existing FluentCart and WooCommerce checkout pages stay separate. New links use cf_product and cf_plan so product query variables from other plugins cannot override the checkout page.

Open Core Commerce → Settings → Store compatibility to check checkout ownership, mixed checkout content, and expiry scheduling. The checker detects WooCommerce, FluentCart, Easy Digital Downloads, SureCart, and WP EasyCart. Repair Core Commerce setup creates or selects an owned checkout and restores a missing expiry schedule. It does not disable another plugin or change its checkout content, carts, or orders.

Core Commerce sends private-page cache headers and contributes checkout/dashboard exclusions to GT Performance. Other cache/CDN configurations need matching exclusions. Compatibility checks do not certify every third-party extension or transfer provider subscriptions.

Customize new license keys

Open Core Commerce → Settings → License key format. Choose lowercase/uppercase hexadecimal, readable Base32, or mixed-case alphanumeric; set random-body length, optional prefix, and groups of four/eight characters. The preview is illustrative and cannot activate a product.

The default is 32 lowercase hexadecimal characters. Minimum lengths preserve at least 128 bits of random entropy. Settings affect newly issued keys only; existing keys are retained exactly. Mixed-case alphanumeric keys are case-sensitive. Key format is currently a store-wide setting.

Native checkout takes a one-time payment. A yearly license term describes the access period; it does not create automatic recurring charges. Provider-backed subscription cancellation must be performed through the payment provider until native lifecycle support is implemented.

Store setup, checkout/dashboard page assignments, and key formatting live in Core Commerce → Settings. Payment configuration remains in the shared Core Forms → Settings → Payments section. Use Manage payment settings above Store compatibility to open it directly. Saving shared settings preserves commerce configuration; saving store setup preserves payment credentials and other shared settings.

Activate Core Commerce

When Core Commerce is inactive, its admin page shows Activate Core Commerce. Activation enables licensing, preserves existing data and shared payment settings, and prepares separate checkout and customer dashboard pages. Running activation again does not duplicate pages. Native checkout and automatic license fulfillment are unavailable while Commerce is inactive.

The overview groups outstanding setup and license work into Next steps. Recent activity can be expanded when needed. Product and settings screens use one workspace surface with fewer nested panels.

Product URLs and content connections

Active products have a virtual URL such as /?product=my-plugin. It renders through the theme without inserting a WordPress post or registering a product CPT. If another store owns the same product slug, the URL uses /?cf_product=my-plugin instead. Product pages link to the separate native checkout.

The product editor includes a releases overview, a copyable product URL, price/checkout previews, and expandable shortcodes. Content connections search pages, posts and public custom content types the merchant can edit. Draft status is shown so a draft connection is not mistaken for published content. Select a search result before saving, or clear the connection.

Customer account

The customer dashboard now has Dashboard, Purchase history, Subscriptions, Licenses, Downloads and Profile sections. Order details are owner-scoped, paid orders have printable receipts, and product/license lists can be searched. Profile edits require a logged-in account and cannot change account email, roles or another user's information. Signed guest links retain read access and site-management capabilities.

Email preferences remain an external/custom integration. Add custom destinations through cf_customer_portal_links; change support/shop destinations with cf_customer_portal_support_url and cf_customer_portal_shop_url.

Set Core Commerce → Settings → Store setup → Support URL to choose the customer portal support destination. Use a full HTTP(S) web address; an external help desk works too. Leave it blank to use the site's /support/ URL.

Product types and galleries

Products support Plugin, Theme, Digital product, Service, and Event types. The editor shows software version/site-limit controls for the existing licensed product types; services show duration, timeframe and scheduling details, while events show dates, timezone, location and access details. Services/events use one-time plans and create order records without software license keys. After-purchase links and instructions are shown only in paid order details, not in public product data. Scheduling and event attendance remain managed through the supplied links.

The product image falls back to the selected type's icon. A custom Media Library icon takes priority. Brief description is the default product summary; create a separate page/post/CPT for longer marketing and SEO content.

Choose product gallery images in the product editor. Display them with the Product Gallery block or [cf_product_gallery product="your-slug" columns="3"]. The virtual product page also includes the gallery. Media-library alternative text and responsive image sizes are used automatically.

Checkout and renewal connections accept either searched WordPress content or a direct HTTP(S) URL. A direct checkout URL is opened as supplied; external payment/fulfillment integrations must be connected separately. Product embedding shortcodes are visible without expanding a toggle.