Forked from strangerstudios/pmpro-custom-prorating.php
Last active
August 29, 2015 14:12
-
-
Save labsecrets/43a1918ce28990a20ef5 to your computer and use it in GitHub Desktop.
This file contains 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 | |
/* | |
Plugin Name: PMPro Customizations | |
Plugin URI: http://www.paidmembershipspro.com/wp/pmpro-customizations/ | |
Description: Custom Prorating Code and Other Code for PMPro | |
Version: .1 | |
Author: Stranger Studios | |
Author URI: http://www.strangerstudios.com | |
*/ | |
/* | |
Custom Prorated payments. When a member chooses to upgrade, | |
he should be charged a pro-rated amount for the new membership level immediately, | |
and the payment date should stay the same. | |
Assumes initial payments are equal to billing amount. | |
When downgrading, the user is not charged and keeps their level until the next payment date. | |
*/ | |
/* | |
Function to check if a level change is a downgrade. | |
*/ | |
function my_isDowngrade($old, $new) | |
{ | |
$monthly_levels = array(1,2,3); //in order from low to high | |
$annual_levels = array(4,5,6); | |
$free_levels = array(7); | |
if($old == $new) | |
{ | |
//same level, not a downgrade | |
return false; | |
} | |
elseif(in_array($old, $free_levels)) | |
{ | |
//Old level is free. Can't downgrade from that. | |
return false; | |
} | |
elseif(in_array($new, $free_levels)) | |
{ | |
//New level is free, old one isn't. Must be a downgrade. | |
return true; | |
} | |
else | |
{ | |
//figure out which comes later in the arrays | |
if(in_array($new, $monthly_levels)) | |
$new_pos = array_search($new, $monthly_levels); | |
else | |
$new_pos = array_search($new, $annual_levels); | |
if(in_array($old, $monthly_levels)) | |
$old_pos = array_search($old, $monthly_levels); | |
else | |
$old_pos = array_search($old, $annual_levels); | |
if($new_pos < $old_pos) | |
return true; | |
else | |
return false; | |
} | |
} | |
//filter level at checkout to prorate | |
function my_pmpro_checkout_level($level) | |
{ | |
//does the user have a level already? | |
if(pmpro_hasMembershipLevel()) | |
{ | |
//get current level | |
global $current_user; | |
$clevel = $current_user->membership_level; | |
//downgrading? | |
if(my_isDowngrade($clevel->id, $level->id)) | |
{ | |
//downgrade, just $0 initial payment | |
$level->initial_payment = 0; | |
//remember the old level for later | |
global $pmpro_checkout_old_level; | |
$pmpro_checkout_old_level = $clevel; | |
//return now | |
return $level; | |
} | |
//get their payment date | |
$morder = new MemberOrder(); | |
$morder->getLastMemberOrder(); | |
//no order? | |
if(empty($morder->timestamp)) | |
return $level; | |
$payment_date = strtotime(date("Y-m-d", $morder->timestamp)); | |
$payment_day = intval(date("j", $morder->timestamp)); | |
//when would the next payment be | |
$next_payment_date = strtotime(date("Y-m-d", $payment_date) . " + " . $clevel->cycle_number . " " . $clevel->cycle_period); | |
//today | |
$today = current_time("timestamp"); | |
//how many days in this period | |
$days_in_period = ceil(($next_payment_date - $payment_date)/3600/24); | |
//how many days have passed | |
$days_passed = ceil(($today - $payment_date)/3600/24); | |
//what percentage | |
$per_passed = $days_passed / $days_in_period; //as a % (decimal) | |
$per_left = 1 - $per_passed; | |
/* | |
Now figure out how to adjust the price. | |
(a) What they should pay for new level = $level->billing_amount * $per_left. | |
(b) What they should have paid for current level = $clevel->billing_amount * $per_passed. | |
What they need to pay = (a) + (b) - (what they already paid) | |
*/ | |
$new_level_cost = $level->billing_amount * $per_left; | |
$old_level_cost = $clevel->billing_amount * $per_passed; | |
$level->initial_payment = round($new_level_cost + $old_level_cost - $morder->total, 2); | |
//just in case we have a negative payment | |
if($level->initial_payment < 0) | |
$level->initial_payment = 0; | |
} | |
return $level; | |
} | |
add_filter("pmpro_checkout_level", "my_pmpro_checkout_level"); | |
/* | |
If downgrading, keep the same billing date | |
*/ | |
function my_pmpro_profile_start_date($date, $order) | |
{ | |
global $current_user, $pmpro_checkout_old_level; | |
if(!empty($pmpro_checkout_old_level) && my_isDowngrade($pmpro_checkout_old_level->id, $order->membership_id)) | |
{ | |
//set profile date to next billing date | |
$next_payment = pmpro_next_payment($current_user->ID); | |
if(!empty($next_payment)) | |
{ | |
$date = date("Y-m-d", pmpro_next_payment($current_user->ID)); | |
//remember for later | |
$pmpro_checkout_old_level->next_payment = date("Y-m-d", $next_payment); | |
} | |
} | |
return $date; | |
} | |
add_filter('pmpro_profile_start_date', 'my_pmpro_profile_start_date', 10, 2); | |
/* | |
If checking out for the same level, keep your old startdate. | |
Updated from what's in paid-memberships-pro/includes/filters.php to run if the user has ANY level | |
*/ | |
function my_pmpro_checkout_start_date_keep_startdate($startdate, $user_id, $level) | |
{ | |
if(pmpro_hasMembershipLevel()) //<-- the line that was changed | |
{ | |
global $wpdb; | |
$sqlQuery = "SELECT startdate FROM $wpdb->pmpro_memberships_users WHERE user_id = '" . $wpdb->escape($user_id) . "' AND membership_id = '" . $wpdb->escape($level->id) . "' AND status = 'active' ORDER BY id DESC LIMIT 1"; | |
$old_startdate = $wpdb->get_var($sqlQuery); | |
if(!empty($old_startdate)) | |
$startdate = "'" . $old_startdate . "'"; | |
} | |
return $startdate; | |
} | |
remove_filter("pmpro_checkout_start_date", "pmpro_checkout_start_date_keep_startdate", 10, 3); //remove the default PMPro filter | |
add_filter("pmpro_checkout_start_date", "my_pmpro_checkout_start_date_keep_startdate", 10, 3); //our filter works with ANY level | |
/* | |
After checkout, if the user downgraded, then revert to the old level and remember to change them to the new level later. | |
*/ | |
function my_pmpro_after_checkout($user_id) | |
{ | |
global $pmpro_checkout_old_level, $wpdb; | |
if(!empty($pmpro_checkout_old_level) && !empty($pmpro_checkout_old_level->next_payment)) | |
{ | |
$new_level = pmpro_getMembershipLevelForUser($user_id); | |
//remember to update to this level later | |
update_user_meta($user_id, "pmpro_change_to_level", array("date"=>$pmpro_checkout_old_level->next_payment, "level"=>$new_level->id)); | |
//change their membership level | |
$wpdb->query("UPDATE $wpdb->pmpro_memberships_users SET membership_id = '" . $pmpro_checkout_old_level->id . "' WHERE membership_id = '" . $new_level->id . "' AND user_id = '" . $user_id . "' AND status = 'active'"); | |
} | |
else | |
delete_user_meta($user_id, "pmpro_change_to_level"); | |
} | |
add_filter('pmpro_after_checkout', 'my_pmpro_after_checkout'); | |
/* | |
Update confirmation message. | |
*/ | |
function my_pmpro_confirmation_message($message, $invoice) | |
{ | |
if(!empty($invoice) && !empty($invoice->user_id)) | |
{ | |
$downgrading = get_user_meta($invoice->user_id, "pmpro_change_to_level", true); | |
if(!empty($downgrading)) | |
{ | |
$dlevel = pmpro_getLevel($downgrading['level']); | |
$message .= "<p>You will be downgraded to " . $dlevel->name . " on " . date(get_option("date_format"), strtotime($downgrading['date'], current_time('timestamp'))) . "."; | |
} | |
} | |
return $message; | |
} | |
add_filter("pmpro_confirmation_message", "my_pmpro_confirmation_message", 10, 2); | |
/* | |
Update account page. | |
*/ | |
function my_the_content($content) | |
{ | |
global $current_user, $pmpro_pages; | |
if(is_user_logged_in() && is_page($pmpro_pages['account'])) | |
{ | |
$downgrading = get_user_meta($current_user->ID, "pmpro_change_to_level", true); | |
if(!empty($downgrading)) | |
{ | |
$downgrade_message = "<p><strong>Important Note:</strong> You will be downgraded to " . $downgrading['level']->name . " on " . date(get_option("date_format"), strtotime($downgrading['date'], current_time('timestamp'))) . "."; | |
$content = $downgrade_message . $content; | |
} | |
} | |
return $content; | |
} | |
add_filter("the_content", "my_the_content"); | |
/* | |
Check for level changes daily. | |
*/ | |
function daily_check_for_membership_changes() | |
{ | |
global $wpdb; | |
//make sure we only run once a day | |
$today = date("Y-m-d", current_time('timestamp')); | |
//get all users with scheduled level changes | |
$level_changes = $wpdb->get_col("SELECT user_id FROM $wpdb->usermeta WHERE meta_key = 'pmpro_change_to_level'"); | |
if(empty($level_changes)) | |
return; | |
foreach($level_changes as $user_id) | |
{ | |
//today? | |
$change = get_user_meta($user_id, 'pmpro_change_to_level', true); | |
if(!empty($change) && !empty($change['date']) && !empty($change['level']) && $change['date'] <= $today) | |
{ | |
//get user's current level | |
$clevel = pmpro_getMembershipLevelForUser($user_id); | |
//change back | |
if(!empty($clevel)) | |
$wpdb->query("UPDATE $wpdb->pmpro_memberships_users SET membership_id = '" . $change['level'] . "' WHERE membership_id = '" . $clevel->id . "' AND user_id = '" . $user_id . "' AND status = 'active'"); | |
//delete user meta | |
delete_user_meta($user_id, 'pmpro_change_to_level'); | |
} | |
} | |
} | |
//hook to run when pmpro_cron_expire_memberships does | |
add_action('pmpro_cron_expire_memberships', 'daily_check_for_membership_changes'); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment