Forked from strangerstudios/pmpro-custom-prorating.php
Last active
August 29, 2015 14:12
Revisions
-
ideadude created this gist
Oct 28, 2014 .There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,280 @@ <?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');