Hey Adrian, Iām also managing a club, and am creating a website where they can go to update their annual membership and I can tie in with Mailchimp. Regarding my example of a member hitting the button twice, thereās actually another way things can go wrong with modifying PayPal button:
What if someone is nearing their expiration date EOT, and decide to renew before they expire. This is a common occurrence. Then if we modify the PayPal button as described in that link you initially shared, then it would make the new EOT the same as the old EOT! Unless you manually change the PayPal button every year, so that, say 3 months prior to your fixed EOT date you set the new EOT 1 year later. Itās not as bad as manually doing it as much as youāre now doing, but youād still have to remember to do it every year.
So, I wrote some code that in the middle of the night loops through all the users, and looks at their EOTās. If the code encounters an EOT that is different than the usual end-of-year EOT, then that means they just signed up for +1 year membership. So if they signed up today, their EOT would be 7/31/2021. The code has a built-in cutoff date (that can be set to whatever you desire), before which their membership goes until the end of the year (12/31/2020 in example above), and after which it extends to the end of following year.
In writing the code and testing it out, I discovered something new about S2Member, which is once an EOT expires, S2 makes it disappear in the userās profile. I find that to be undesirable, because Iād like a record of past members, and when their membership last expired. So, to solve this, I added some extra code, to store a new custom field ālast_eot_yearā, which stores just the year (e.g. 2019). It keeps current with the year of the real EOT, but once the real EOT disappears, the Last EOT Year remains as a permanent record. If you donāt want that functionality, then of course erase that part of code. But if you like it, then you need to create custom field in S2Member before running the code.
To implement the code, I presume you have access to your WP file directory? In the directory wp-content, if itās not already there then create a subdirectory called mu-plugins. Then save the following code in a file called whatever you want, but people here like to call it s2-hacks.php.
The code creates a scheduled task (ācronā job), and technically it will only run at that scheduled time if thereās somebody accessing the website at that time. Otherwise, it will execute after that scheduled time, the first thing once someone accesses site. If you want it to run absolutely at the scheduled time, regardless of user activity, then need to schedule an absolute cron job. I plan to do that once I migrate site over to HostGator. Hereās their article on how to do that:
https://www.hostgator.com/help/article/how-to-replace-wordpress-cron-with-a-real-cron-job
Please test this code out on a test site (not real users) before going live on your real site! I recommend installing plugin ācrontrolā, because it lets you run the cron job instantly, which is helpful during testing.
Good luck, and let me know if you have questions about the code. Hereās the code:
<?php
//Schedule an action if it's not already scheduled
if ( ! wp_next_scheduled( 'uea_cron_hook' ) ) {
wp_schedule_event( strtotime('10:00:00'), 'daily', 'uea_cron_hook' ); //UTC time
}
//Hook into that action that'll fire daily
add_action( 'uea_cron_hook', 'uea_cron_function' );
//Function that runs on cron
function uea_cron_function() {
$users = get_users('orderby=ID');
date_default_timezone_set('UTC');
$eot_day = '12/31/'; //Adjust EOT date as desired
$eot_hour = ' 20:00:00'; //EOT hour (20:00 UTC = noon PST on 12/31)
$cutoff_day = '10/01/'; //Adjust cutoff date as desired
$cutoff_hour = ' 07:00:00'; //cutoff hour (07:00 UTC = 00:00 PDT)
foreach ($users as $user){
$user_id = $user->ID;
$user_role = $user->roles[0]; //roles is an array with one element
if ($user_role != 'administrator') {
// Adjust EOT if necessary.
$keymeta = 'wp_s2member_auto_eot_time';
$old_eot_time = intval(get_user_meta($user_id, $keymeta, true)); //if not null, then UTC time (sec's since 1970)
if ($old_eot_time) { //non-zero EOT
$eot_year = date('Y', $old_eot_time); //Year of current EOT, 4-digit format (string)
$cutoff_time = strtotime($cutoff_day . $eot_year . $cutoff_hour);
if ($old_eot_time < $cutoff_time) { //did not make cutoff time, so use previous year
$eot_year = strval(intval($eot_year)-1);
}
$new_eot_time = strtotime($eot_day . $eot_year . $eot_hour);
if ($new_eot_time != $old_eot_time) { //A change was made to EOT, so update user
update_user_meta($user_id, $keymeta, strval($new_eot_time));
}
// Also adjust Last EOT if necessary.
$last_eot_year = '';
$keymeta2 = 'wp_s2member_custom_fields';
$valuemeta = get_user_meta($user_id, $keymeta2, true);
if ($valuemeta) { //checks that there is non-empty custom field data
foreach ($valuemeta as $keycustom => $valuecustom) { //loop through associative array
if ($keycustom == 'last_eot_year' && $valuecustom) { //There is a non-null Last EOT year
$last_eot_year = $valuecustom;
}
}
}
if ($eot_year != $last_eot_year) { //A change was made to EOT, so update Last EOT year
if (!$valuemeta) $valuemeta = array();
$valuemeta['last_eot_year'] = $eot_year;
update_user_meta($user_id, $keymeta2, $valuemeta);
}
}
}
}
}
?>