3.9
Latest7 new23 improvements10 security
New
- Merged the Subscription Delays Add On into core. The new First Recurring Payment setting on levels and custom pricing discount codes can delay the first recurring payment by a number of days or until a date set with a date pattern. #3630 (@dparker1005, @kimcoleman)
- Merged the Set Expiration Dates Add On into core. Levels and custom pricing discount codes can expire memberships on a date set with a date pattern. #3630 (@dparker1005, @kimcoleman)
- Added percentage and fixed amount discount code types alongside the existing per-level custom pricing. The discount is calculated from each level's current pricing and can apply to the initial payment, recurring payments, or both, while the billing cycle, trial, and expiration come from the level. #3727 (@dparker1005)
- Added a migration tool for deprecated gateways, opened from the "Migrate Subscriptions Off This Gateway" button on the gateway's Payment Settings page. It recreates active subscriptions at Stripe (or sets the memberships to expire), can email members, cancels the old gateway subscriptions, and supports a dry run. A final step deletes the gateway's stored API credentials and stops loading the gateway; orders and subscriptions are kept. #3700 (@dparker1005)
- Added WordPress Abilities API support (WordPress 6.9+) for querying membership levels, orders, subscriptions, and PMPro search results, and for viewing, changing, and cancelling a member's memberships. Abilities are available over the REST API and to MCP clients through an MCP adapter plugin. #3736, #3757 (@mircobabini, @dparker1005)
- Added a `wp pmpro` WP-CLI command set for memberships, members, levels, orders, and subscriptions, and the `pmpro_cli_init` action for Add Ons to register their own commands. #3740, #3757 (@flintfromthebasement, @dparker1005)
- Added `/pmpro/v1/memberships`, `/pmpro/v1/orders`, and `/pmpro/v1/subscriptions` REST API collection endpoints with filtering, sorting, and pagination. #3740, #3757 (@flintfromthebasement, @dparker1005)
Improved
- Added an "Awaiting Payment Method" filter and tag on the Subscriptions list, an admin notice, and a Membership Account page notice for subscriptions migrated to Stripe that have no payment method on file. The default Recurring Payment Reminder email now asks these members to add a payment method. #3700 (@dparker1005)
- Added the "Deprecated Gateway Stripe Migration" and "Deprecated Gateway Checkout Required" email templates, shown on sites that still use a deprecated gateway. #3700 (@dparker1005)
- The "Update Billing Info" links on the Membership Account and Billing pages no longer require the subscription to have an order. The Billing page link now only shows for subscriptions on the active gateway when that gateway supports payment method updates, matching the Membership Account page. #3700 (@dparker1005)
- Added the `pmpro_deprecated_gateway_batch_size` filter to set how many subscriptions the deprecated gateway migration processes per batch. #3700 (@dparker1005)
- Added a captcha to the login and lost password forms, including wp-login.php, when reCAPTCHA or Cloudflare Turnstile is enabled. The captcha is only shown after a failed login or other suspicious activity from the visitor's IP address in the last 15 minutes. #3765 (@dparker1005)
- Replaced the separate reCAPTCHA and Cloudflare Turnstile settings with a single Captcha setting on the Security Settings page, so only one captcha runs at a time. Existing settings carry over, and sites that had both enabled now use reCAPTCHA. Added the `pmpro_captcha_services` filter for registering other captcha services. #3765 (@dparker1005)
- Added the `pmpro_login_form_before_submit_button` action and the `pmpro_authenticate_login_checks`, `pmpro_login_forms_handler_message`, and `pmpro_login_forms_handler_msgt` filters to the login flow. #3765 (@dparker1005)
- A failed payment at checkout or on the Update Billing page now requires a new reCAPTCHA or Cloudflare Turnstile check before the next attempt. Thanks to Freelance Studio for the report. #3885, #3887 (@dparker1005)
- Membership Account page now shows when a membership's latest payment is past due and shows a card for memberships with a pending checkout that is waiting on payment. #3714 (@kimcoleman, @dparker1005)
- Added the `pmpro_membership_account_after_pending_level_card_content` action for adding content to a pending membership card on the Membership Account page. #3714 (@kimcoleman, @dparker1005)
- Added an optional Advanced Setting to automatically delete abandoned checkout users (Potential Spam Checkouts) after 30 days. Users with any membership history, users who can edit posts, and users who have written posts are never deleted. Added the `pmpro_abandoned_signup_deletion_days` filter to change the retention period. #3737, #3901 (@dparker1005)
- Added Status, Usage and Level filters to the Discount Codes admin page. #3896 (@dparker1005)
- Added a date filter (All Time, Last 7 Days, Last 30 Days, Last 12 Months, or a custom range) to the Email Log report. #3692 (@dwanjuki)
- The Email Log now records the file names of email attachments and shows them in the log details and the personal data exporter. #3773 (@faisalahammad)
- Added the `{{ billing_update_url }}` email template variable to the Payment Failure email and linked to the Billing page in its default body. #3892 (@dparker1005)
- The Admin Activity Email now reports active members and active memberships as separate numbers when they differ. #3768 (@flintfromthebasement, @dparker1005)
- Added Product/Offer JSON-LD structured data for membership levels on the levels page, the checkout page, and pages using the Single Membership Level block. It can be turned off with the Structured Data setting on the Advanced Settings page, and developers can customize it with the new `pmpro_structured_data_*` filters. #3735 (@flintfromthebasement, @dparker1005)
- Added an optional Level Image setting on the edit level page, used as the product image in membership level structured data. #3735, #3906 (@flintfromthebasement, @dparker1005)
- Added Elementor v4 (atomic elements) support to PMPro content restriction controls. Added the `pmpro_elementor_atomic_element_types` filter to change which atomic elements support restriction. #3709 (@dparker1005)
- Added a new `pmpro_view_as` capability so the "View As" toolbar in the admin bar can be granted to roles that should not have `manage_options`. #3786 (@faisalahammad)
- Added the `pmpro_memberslist_sortable_columns` and `pmpro_memberslist_sql_join` filters and made the First Name and Last Name columns sortable in the Members List. #3805, #3902 (@faisalahammad, @dparker1005)
- Improved Members List performance for the default and single-level views by no longer grouping rows when each row is already one member and level. Added the `pmpro_members_list_group_rows` filter so custom code that adds joins through `pmpro_members_list_sql` can turn grouping back on. #3833 (@flintfromthebasement)
- Added the `pmpro_is_page` function to safely check PMPro pages, with optional shortcode and block detection for custom pages. #3810 (@faisalahammad, @dparker1005)
Security
- Improved escaping and SQL query preparation throughout the plugin. #3827 (@dparker1005)
- Added direct file access protection to plugin files. #3828 (@dparker1005)
- Improved request input handling and redirect safety throughout the plugin. #3829 (@dparker1005)
- The Authorize.net gateway now verifies TLS certificates when connecting to Authorize.net. #3916 (@dparker1005)
- The 2Checkout gateway now verifies TLS certificates when sending API requests. #3917 (@dparker1005)
- The `[pmpro_member]` shortcode is now also removed from newly added post meta saved by users who cannot edit users. #3921 (@dparker1005)
- The REST API order endpoint now only includes order notes for users with the `pmpro_orders` capability. #3918 (@dparker1005)
- Values in the members, orders, and logins report CSV exports that start with a spreadsheet formula character are now prefixed with a single quote so they are not run as formulas. #3922 (@dparker1005)
- The admin redirect for missing members, orders, subscriptions, discount codes, and levels now only runs for users who can access the Memberships menu. #3920 (@dparker1005)
- The Billing page now redirects to the Membership Account page when the requested subscription does not exist. #3919 (@dparker1005)