Skip to content

Instantly share code, notes, and snippets.

@pbrocks
Created August 15, 2018 20:33
Show Gist options
  • Save pbrocks/3847e3767b2fca23c0975f2502f301c8 to your computer and use it in GitHub Desktop.
Save pbrocks/3847e3767b2fca23c0975f2502f301c8 to your computer and use it in GitHub Desktop.
Since PMPro doesn't set the expiration date to allow for recurring billing, set cancellation date to match next payment date.
<?php // do not include in customizations plugin
/**
*
* Change cancellation date to match next payment
*
* Add to PMPro Customizations plugin
*/
add_action( 'pmpro_after_change_membership_level', 'pmpro_cancel_at_end_of_period', 10, 2 );
add_filter( 'pmpro_email_body', 'pmpro_email_body_for_cancel_msg', 10, 2 );
/**
* Change cancellation to set expiration date for next payment instead of cancelling immediately.
* Assumes monthly membership levels.
* Assumes orders are generated for each payment (i.e. your webhooks/etc are setup correctly).
*
* @param (int) $level_id -- The membership levelId we're changing
* @param (int) $user_id -- The member we're changing levels for.
*/
function pmpro_cancel_at_end_of_period( $level_id, $user_id ) {
global $pmpro_pages, $wpdb;
// Make sure we're on the 'cancel' page (for PMPro).
if ( is_page( $pmpro_pages['cancel'] ) ) {
/*
* okay, let's give the user his old level back with an expiration based on his subscription date
*/
/* Fetch the last order */
$order = new MemberOrder();
$order->getLastMemberOrder( $user_id, 'cancelled' );
// Fetch the levelId representing their most recent (old) membership level.
$level = $wpdb->get_row(
$wpdb->prepare(
"
SELECT *
FROM {$wpdb->pmpro_memberships_users}
WHERE membership_id = %d AND user_id = %d
ORDER BY id DESC
LIMIT 1
",
$order->membership_id,
$user_id
)
);
// Not allowed to do this unless there's both a levelId and an order located in the system
// This is probably wrong since $order rarely (never?) is empty.
if ( ( ! isset( $order->user_id ) ) || empty( $level ) ) {
return false;
}
if ( empty( $level->cylcle_number ) ) {
return false;
}
// Calculate the "last payment date" (using "today").
$lastdate = date( 'Y-m-d', $order->timestamp );
// Calculating the "next scheduled date"
$nextdate = $wpdb->get_var(
$wpdb->prepare(
"
SELECT UNIX_TIMESTAMP(%s + INTERVAL %d {$level->cycle_period})
",
$lastdate,
$level->cycle_number
)
);
// if the date in the future?
if ( $nextdate - current_time( 'timestamp' ) > 0 ) {
// Set their level to the one they're currently at, but leave the expiration date set to their next billing date.
$sql = $wpdb->prepare(
"
SELECT *
FROM $wpdb->pmpro_memberships_users
WHERE ( membership_id = %d ) AND ( user_id = %d )
ORDER BY id
DESC LIMIT 1
",
$order->membership_id,
$user_id
);
$old_level = $wpdb->get_row( $sql, ARRAY_A );
$old_level['enddate'] = date( 'Y-m-d H:i:s', $nextdate );
// disable this hook so we don't loop
remove_action( 'pmpro_after_change_membership_level', 'pmpro_cancel_at_end_of_period', 10, 2 );
remove_action( 'pmpro_after_change_membership_level', 'pmpro_membership_level_config', 10, 2 );
remove_action( 'pmpro_after_change_membership_level', 'pmpro_clear_upcoming_appointments', 11, 2 );
remove_action( 'pmpro_after_change_membership_level', 'pmpro_after_change_membership_level', 10, 2 );
// change level
pmpro_changeMembershipLevel( $old_level, $user_id );
// add the action back just in case
add_action( 'pmpro_after_change_membership_level', 'pmpro_cancel_at_end_of_period', 10, 2 );
add_action( 'pmpro_after_change_membership_level', 'pmpro_membership_level_config', 10, 2 );
add_action( 'pmpro_after_change_membership_level', 'pmpro_clear_upcoming_appointments', 11, 2 );
add_action( 'pmpro_after_change_membership_level', 'pmpro_after_change_membership_level', 10, 2 );
// change message shown on cancel page
add_filter( 'gettext', 'pmpro_gettext_cancel_text', 10, 3 );
}
}
}
/**
* @param $translated_text -- Text to replace/update
* @param $text -- The text
* @param $domain
*
* @return string
*/
function pmpro_gettext_cancel_text( $translated_text, $text, $domain ) {
if ( ( $domain == 'pmpro' ) &&
( $text == 'Your membership has been cancelled.' ) ) {
global $current_user;
$translated_text = 'Your membership has been cancelled. Your access to schedule and join new sessions will expire on ' .
date_i18n( get_option( 'date_format' ), pmpro_next_payment( $current_user->ID, 'cancelled' ) ) .
', but you may schedule new sessions until then. Once your membership expires, any scheduled sessions ' .
'will be removed automatically.';
}
return $translated_text;
}
/**
* If the user cancels, send a message about when the cancellation will actually occur.
*
* @param (string) $body - The content of the message (we'll append the cancellation date to it)
* @param (object) $email -- The email object.
*
* @return string -- The new body of the email message.
*/
function pmpro_email_body_for_cancel_msg( $body, $email ) {
if ( $email->template == 'cancel' ) {
global $wpdb;
$user_id = $wpdb->get_var(
"
SELECT ID
FROM $wpdb->users
WHERE user_email = '" . esc_sql( $email->email ) . "' LIMIT 1"
);
if ( ! empty( $user_id ) ) {
$expiration_date = pmpro_next_payment( $user_id );
// Only update the body of the message if the date is in the future.
if ( $expiration_date - current_time( 'timestamp' ) > 0 ) {
$body .= '<p>Your access will expire on ' . date( get_option( 'date_format' ), $expiration_date ) . '.</p>';
}
}
}
return $body;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment