Subscriptions
The subscriptions module adds products with recurring payments. Customers buy subscriptions with manual renewal, and the administrator manages them in WooCommerce.
How it works
Section titled “How it works”- The administrator creates a “Subscription” product type with a cycle and price
- The customer purchases a subscription and pays the first order
- The plugin creates a subscription with “Active” status
- Before the renewal date, the customer receives a reminder email
- On the renewal date, the plugin creates a renewal order
- The customer pays the renewal order (manual renewal)
- The cycle repeats until the subscription is cancelled
Configuration
Section titled “Configuration”Go to WooCommerce > Settings > Polski > PRO Modules > Subscriptions.
The module is controlled by the option:
polski_subscriptionsGeneral settings
Section titled “General settings”| Setting | Description |
|---|---|
| Enable subscriptions | Activates the module |
| Renewal mode | Manual (customer pays the order) |
| Reminder days | How many days before renewal to send a reminder (default 3) |
| Grace period | How many days after the renewal date the subscription stays active (default 7) |
| Automatic suspension | Suspend subscription after the grace period expires |
Creating a subscription product
Section titled “Creating a subscription product”- Go to Products > Add New
- Select product type: Subscription
- Configure the price and cycle:
| Field | Description |
|---|---|
| Subscription price | Amount per billing period |
| Billing period | Day / Week / Month / Year |
| Period length | Number of periods (e.g. 1 month, 3 months) |
| Initial price | Optional - different price for the first period |
| Activation fee | Optional - one-time fee on the first order |
| Renewal limit | 0 = no limit, or number of renewals |
- Publish the product
Initial price vs renewal price
Section titled “Initial price vs renewal price”The plugin supports scenarios where the price for the first period differs from the price for subsequent periods. Typical use cases:
- free trial or reduced-price trial period
- promotional introductory price
- activation fee + lower recurring price
The initial price is applied only to the first order. Subsequent renewal orders use the standard subscription price.
Subscription lifecycle
Section titled “Subscription lifecycle”Pending → Active → On Hold → Active → ... → Expired → Cancelled| Status | Description |
|---|---|
| Pending | Awaiting payment of the first order |
| Active | Active - customer has access to the product |
| On Hold | Suspended - renewal order awaiting payment |
| Expired | Expired - renewal count reached the limit or grace period passed |
| Cancelled | Cancelled by the customer or administrator |
Renewals
Section titled “Renewals”Manual renewal
Section titled “Manual renewal”In the current version, the plugin supports manual renewals. This means that:
- The plugin creates a renewal order with “Pending payment” status
- The customer receives an email with a link to pay the order
- The customer pays the order using their chosen payment method
- After payment, the subscription is renewed for the next period
Renewal process
Section titled “Renewal process”The plugin checks subscriptions due for renewal daily using WP cron:
polski_daily_maintenanceThe cron task runs once daily and performs:
- checking subscriptions whose renewal date falls on today or earlier
- creating renewal orders for subscriptions requiring renewal
- suspending subscriptions that have exceeded the grace period
- expiring subscriptions that have reached the renewal limit
Email reminders
Section titled “Email reminders”The plugin sends email reminders before the renewal date:
| When | Content | |
|---|---|---|
| Renewal reminder | X days before renewal | Information about the upcoming renewal, amount, link to the panel |
| Renewal order | On the renewal date | Order to pay with a payment link |
| Subscription suspended | After payment due date passes | Information about suspension, link to pay |
| Subscription expired | After grace period passes | Information about expiration, link to repurchase |
Email templates can be customized in WooCommerce > Settings > Emails.
My Account panel
Section titled “My Account panel”The module adds a /polski-subscriptions endpoint to the customer’s My Account panel. The endpoint is available at:
/moje-konto/polski-subscriptions/Subscription list
Section titled “Subscription list”The customer sees a table with subscriptions:
| Column | Description |
|---|---|
| Product | Subscription product name |
| Status | Current subscription status |
| Price | Amount per period |
| Next renewal | Next renewal date |
| Actions | Cancel / Pay renewal |
Subscription details
Section titled “Subscription details”After clicking on a subscription, the customer sees:
- full subscription data (product, price, cycle, dates)
- renewal history (list of associated orders)
- subscription cancellation button
- button to pay a pending renewal (if applicable)
Cancelling a subscription
Section titled “Cancelling a subscription”The customer can cancel an active subscription from the My Account panel. Cancellation:
- changes the subscription status to “Cancelled”
- the subscription remains active until the end of the current paid period
- the customer is informed about the access end date
polski_pro/subscription/status_changed
Section titled “polski_pro/subscription/status_changed”Action fired after a subscription status change.
/** * @param int $subscription_id ID subskrypcji * @param string $new_status Nowy status * @param string $old_status Poprzedni status */do_action('polski_pro/subscription/status_changed', int $subscription_id, string $new_status, string $old_status);Example:
add_action('polski_pro/subscription/status_changed', function (int $subscription_id, string $new_status, string $old_status): void { if ($new_status === 'cancelled') { $subscription = polski_pro_get_subscription($subscription_id); // Wysłanie ankiety o powód rezygnacji wp_mail( $subscription->get_customer_email(), 'Szkoda, że odchodzisz', 'Powiedz nam, dlaczego anulujesz subskrypcję: https://example.com/ankieta' ); }}, 10, 3);polski_pro/subscription/renewal_created
Section titled “polski_pro/subscription/renewal_created”Action fired after a renewal order is created.
/** * @param int $order_id ID zamówienia odnowienia * @param int $subscription_id ID subskrypcji */do_action('polski_pro/subscription/renewal_created', int $order_id, int $subscription_id);Example:
add_action('polski_pro/subscription/renewal_created', function (int $order_id, int $subscription_id): void { $order = wc_get_order($order_id); $order->add_order_note( sprintf('Zamówienie odnowienia dla subskrypcji #%d', $subscription_id) );}, 10, 2);polski_pro/subscription/renewal_paid
Section titled “polski_pro/subscription/renewal_paid”Action fired after a renewal order is paid.
/** * @param int $order_id ID zamówienia odnowienia * @param int $subscription_id ID subskrypcji */do_action('polski_pro/subscription/renewal_paid', int $order_id, int $subscription_id);Renewal reminder hooks (1.8.2+)
Section titled “Renewal reminder hooks (1.8.2+)”The reminder engine (14 + 7 days before renewal by default) exposes filters and actions:
// Customise windows (days before renewal)add_filter('polski_subscription_reminder_windows', fn ($w) => ['first' => 21, 'second' => 7, 'last' => 1]);
// Subject / body / headers filtersadd_filter('polski_subscription_reminder_subject', fn ($s, $sub, $type) => "[$type] $s", 10, 3);add_filter('polski_subscription_reminder_body', fn ($b, $sub, $type) => $b . "\n\nThanks!", 10, 3);add_filter('polski_subscription_reminder_headers', fn () => ['Content-Type: text/html; charset=UTF-8']);
// Skip a specific subscriptionadd_filter('polski_subscription_skip_reminder', fn ($skip, $sub) => $sub->productId === 42, 10, 2);
// Observe dispatchadd_action('polski_subscription_reminder_sent', fn ($sub, $type, $days) => null, 10, 3);add_action('polski_subscription_reminder_failed', fn ($sub, $type) => null, 10, 2);Price-change notifications (1.8.3+)
Section titled “Price-change notifications (1.8.3+)”SubscriptionRepository::updateRecurringAmount() detects an amount change and emails the customer with old/new price, effective next billing date and a one-click cancel link (EU consumer-protection requirement).
add_action('polski_subscription_amount_changed', function (int $id, float $prev, float $next) { error_log("Subscription $id: $prev -> $next");}, 10, 3);
add_filter('polski_subscription_amount_change_body', fn ($body, $sub, $prev, $next) => $body, 10, 4);add_action('polski_subscription_amount_change_notified', fn ($sub, $prev, $next, $sent) => null, 10, 4);Admin panel
Section titled “Admin panel”Subscription list
Section titled “Subscription list”Go to WooCommerce > Subscriptions. The table contains:
- subscription ID
- customer (first name, last name, email)
- product
- status
- price and cycle
- next renewal date
- creation date
Available filters: status, product, creation date.
Editing a subscription
Section titled “Editing a subscription”The administrator can:
- change the subscription status
- change the next renewal date
- change the price (affects subsequent renewals)
- add a note
- browse status history and associated orders
Common issues
Section titled “Common issues”Renewal orders are not being created
Section titled “Renewal orders are not being created”- Check if WP-Cron is working properly (
wp_cronis being called) - Go to Tools > Scheduled Actions and check if the
polski_daily_maintenancetask is scheduled - Verify that the subscription has “Active” status and a correct renewal date
Customer does not receive reminders
Section titled “Customer does not receive reminders”- Check the WooCommerce email configuration
- Verify that the reminder email template is enabled
- Check the “Reminder days” setting - whether it is greater than 0
Subscription does not change status after payment
Section titled “Subscription does not change status after payment”- Check if the renewal order has a correct association with the subscription
- Verify WooCommerce logs for errors
- Check if the payment gateway correctly changes the order status