Created
April 29, 2026 13:48
-
-
Save andrewlimaza/d552e9dbd6dd5be471095cf7e8b6aa87 to your computer and use it in GitHub Desktop.
Set billing start date (subscription delay) to expiration date when member is renewing for recurring level
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| /** | |
| * Move the members subscription start date based on their remaining days of current level that has an expiration date. | |
| * Note: Do not set initial payment to $0, let members pay ahead for their next billing period before starting subscriptions. | |
| * Useful for any migration where we cannot migrate the subscription and need to checkout again. | |
| */ | |
| function my_pmpro_renewal_defer_startdate( $checkout_level ) { | |
| // Only run on the frontend during checkout | |
| if ( ! function_exists( 'pmpro_getMembershipLevelForUser' ) ) { | |
| return $checkout_level; | |
| } | |
| $user_id = get_current_user_id(); | |
| if ( ! $user_id ) { | |
| return $checkout_level; | |
| } | |
| // Only for recurring levels. | |
| if ( ! pmpro_isLevelRecurring( $checkout_level ) ) { | |
| return $checkout_level; | |
| } | |
| // Get the member's current level | |
| $current_level = pmpro_getMembershipLevelForUser( $user_id ); | |
| // Only proceed if they already hold this exact level (renewal scenario) | |
| if ( empty( $current_level ) || (int) $current_level->id !== (int) $checkout_level->id ) { | |
| return $checkout_level; | |
| } | |
| // Only defer if there's a future expiration date | |
| if ( empty( $current_level->enddate ) || $current_level->enddate === '0000-00-00 00:00:00' ) { | |
| return $checkout_level; | |
| } | |
| // Seconds remaining on the current level from today until the enddate. | |
| $days_remaining = $current_level->enddate - time(); | |
| // If there are any days remaining, they still pay the full initial amount BUT they also get their subscription first payment date to be delayed for remaining days. | |
| if ( $days_remaining > 0 ) { | |
| // The original first-billing date is now + cycle_number cycle_period (e.g. +1 Year). | |
| $original_startdate = strtotime( '+' . (int) $checkout_level->cycle_number . ' ' . $checkout_level->cycle_period ); | |
| $new_startdate = $original_startdate + $days_remaining; | |
| $checkout_level->startdate = date( 'Y-m-d', $new_startdate ); | |
| // Adjust the text at checkout to show a small hint that billing will only start on a specific date. | |
| add_filter( 'pmpro_level_cost_text', 'my_pmpro_show_checkout_level_startdate_in_cost_text', 10, 2 ); | |
| } | |
| return $checkout_level; | |
| } | |
| add_action( 'pmpro_checkout_level', 'my_pmpro_renewal_defer_startdate' ); | |
| // Show the checkout level startdate in the cost text so customer's know. | |
| function my_pmpro_show_checkout_level_startdate_in_cost_text( $cost, $level ) { | |
| if ( ! empty( $level->startdate ) ) { | |
| $start_date = date_i18n( get_option( 'date_format' ), strtotime( $level->startdate ) ); | |
| $cost .= sprintf( ' <small>(%s %s)</small>', esc_html__( 'Billing starts on', 'paid-memberships-pro' ), esc_html( $start_date ) ); | |
| } | |
| return $cost; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment