Various mods to core plugin

Hi guys

I have had some requests from a client for features which dont seem to be a part of this plugin, though I feel should be because they just make sense to be there.

The client would like admin notifications when a user has cancelled their subscription, they offer a 14 day trial so most cancellations would probably be within this period. I can see in S2Member > API/Notifications > Cancellation Notifications that this could be set up using a mu-plugin and have followed the link to https://s2member.com/kb-article/building-an-api-notification-handler-webhook/ but can I just copy the function and change s2_payment_notification to s2_cancellation_notification?

In the code example on that page, it shows how to set up the function and pull in the values from the URL etc but it doesn’t then demonstrate how to send the mail, are there any examples of this?

The client then also wants the user to receive a cancellation notification with a different message?

Thanks in advance for your help.

Further to the above, here’s where I am up to, it’s not currently working…

My notification URL is:
http://xxx.xx.xxx.xx/~devs/pilates/wp-content/mu-plugins/s2-cancel-notification.php?s2_cancel_notification=yes&user_id=%%user_id%%

And in http://xxx.xx.xxx.xx/~devs/pilates/wp-content/mu-plugins/s2-cancel-notification.php I have:

<?php
add_action('init', 's2_cancel_notification');
function s2_cancel_notification()
{
    if(!empty($_GET['s2_cancel_notification']) && $_GET['s2_cancel_notification'] === 'yes')
        // ↑ In my URL, I have `?s2_cancel_notification=yes`, that's what I'm looking for here.
    {
        if(!empty($_GET['user_id']))
        // In my URL, I have `&user_id=%%user_id%%`, that's what I'm looking for here.
        {
            $user_id     = (integer)$_GET['user_id']; // I'm expecting an integer in this value.

            $user = new WP_User($user_id); // Get a WordPress User object instance so I can work with this customer.

            // I could also collect details about this user, by accessing properties of my WP_User object instance.
            $first_name = $user->first_name;
            $last_name  = $user->last_name;
            $email      = $user->user_email;
            $username   = $user->user_login;

            // I could also log this transaction, by creating a log entry in a static text file on-site.
            file_put_contents(WP_CONTENT_DIR.'/plugins/s2member-logs/sharelog.txt', 'Cancellation Notification Received for User ID: '.$user_id."\n", FILE_APPEND);
        }
        exit; // We can exit here. There's no reason to continue loading WordPress in this case.
    }
}

I have also created a text file here: WP_CONTENT_DIR.’/plugins/s2member-logs/sharelog.txt

When I cancel a user, nothing happens, no email (despite my email address being in the Email Transaction Log field and nothing is put in my log file.

Any ideas? Thanks.

You might be right with this specific issue. But, if everyone who said that got their wish, the plugin would be huge, slow, and bloated – and essentially useless. Adding a few mu-plugins seems a very small price to pay for keeping it lean and quick.

The problems with your code are (a) that you are trying to use s2Member-specific details when you just need to use core WP stuff, and (b) your hook is wrong. Init fires when WP is setting up. You need to hook to the cancellation itself.

So here are a couple of functions that will send an email to the former member and to the admin:

<?php
/* SEND EMAILS WHEN MEMBERSHIP IS DELETED */
function kts_delete_user_email( $user_id ) { // email to ex-member
	global $wpdb;
	$user_obj = get_userdata( $user_id );
	$email = $user_obj->user_email;
	$to = $email;
	$subject = "Your account has been deleted";
	$message = 'Hello, ' . $user_obj->display_name . '!' "\r\n\r\n";
	$message = 'Your membership on the ' . get_bloginfo ( 'name' ) . ' website has now been deleted. We are sorry to see you go.' "\r\n";
	wp_mail( $to, $subject, $message );
}
add_action( 'delete_user', 'kts_delete_user_email' );

function kts_admin_email_on_cancel( $user_id ) { // email to admin
	global $wpdb;
	$user_obj = get_userdata( $user_id );
	$to = get_option( 'admin_email' );
	$subject = "A member has cancelled";
	$message = 'The membership of ' . $user_obj->display_name . ' on the ' . get_bloginfo ( 'name' ) . ' website has now been cancelled.' "\r\n";
	wp_mail( $to, $subject, $message );
}
add_action( 'delete_user', 'kts_admin_email_on_cancel' );

Hi Tim

Thanks for your reply, I agree with your opening statement.

You may have realised but I copied majority of my script from the example in the S2member KB. The client has decided to ‘downgrade/revoke’ access rather than delete the user entirely because they offer a 14 day trial so they don’t want the same user to register more than once with the same email address if deleted, though I have explained that a user can just use a second email address for a further trial!

So as above, I have tried to get an entry inputting in to a log file mainly to test that the script is working, but it didn’t seem to do anything. I’ve never really truly understood the add_action hooks so not sure what I should be replacing init with but i’m guessing that as we’re not deleting users, it wouldn’t be that in your example.

So I have stripped out the code I have a little bit, and have the following:

<?php
add_action('????', 's2_cancel_notification');
function s2_cancel_notification()
{
    if(!empty($_GET['s2_cancel_notification']) && $_GET['s2_cancel_notification'] === 'yes')
    {
        if(!empty($_GET['user_id']))
        {
            $user_id     = (integer)$_GET['user_id'];
            $user = new WP_User($user_id);

            $first_name = $user->first_name;
            $last_name  = $user->last_name;
            $email      = $user->user_email;
            $username   = $user->user_login;

            file_put_contents(WP_CONTENT_DIR.'/plugins/s2member-logs/sharelog.txt', 'Cancellation Notification Received for User ID: '.$user_id.' with username: '.$username."\n", FILE_APPEND);
        }
        exit;
    }
}

And if I can just get this log file working then i’d like to use your email example above within there too.

Thanks

No, I didn’t realize. I just wrote my functions for use on one of my own sites. So I know they work.

Ahh OK, yeh I copied majority from here: https://s2member.com/kb-article/building-an-api-notification-handler-webhook/

But as my PHP knowledge (especially with hooks/functions) is limited I have no idea what I really need to change in order to get it to work, though I can follow the process to see what should be happening, but isn’t.

Adrian, I am not a developer either. I just read the WP Codex and work out what I need.

Right, this is really annoying me now. I’ve stripped the code riiiiiight down to the simplest thing, and it still doesn’t work:

<?php
require( dirname(dirname(dirname( __FILE__ ))) . '/wp-load.php' );
function s2_cancel_notification()
{
      if($_GET['user_id'])
      {
            file_put_contents(dirname(dirname( __FILE__)) . 'sharelog.txt', 'testing', FILE_APPEND);
      }

}
add_action('init','s2_cancel_notification');

What’s going wrong?!

I told you: you’re using the wrong hook.

You have taken an example designed for payments and are trying to make it work for cancellations. It won’t. For a start, the user doesn’t exist after canceling, so you’re effectively asking for a search for something that doesn’t exist.

Modify the code I gave you, and stop trying to work with the wrong model.

Sorry Tim but I have to disagree with that, a) the plugin is set to just revoke access after cancelling, not delete the user, plus they get 14 day free trial so during my testing I can register, then cancel and would still have 14 days access before the EOT revokes access, and b) it states in the Wordpress codex: _init is useful for intercepting $_GET or $POST triggers which is exactly what i’m trying to do.

Well, why didn’t you say so before? Then I wouldn’t have bothered with this thread at all.

But I’d still say you’re using the wrong hook. You need something like set_user_role

I did, in my first reply to you haha… OK i’ll try that hook. I’ve just tried again with logging enabled but can’t see anything in the logs related to the notifications so perhaps they’re not part of the logging process.

So you did – apologies!

An alternative hook would be profile_update

I’ve just watched the prehistoric YouTube tutorial on API/Notifications where the guy didn’t even have an add_action so have sort of copied his:

<?php
require( dirname(dirname(dirname( __FILE__ ))) . '/wp-load.php' );

if($_GET['secretKey'] === 'mdg4s6hj6dfs4g')
      {

      if($_GET['user_id'])
            {

                  $user_id     = (integer)$_GET['user_id']; // I'm expecting an integer in this value.

                  $user = new WP_User($user_id); // Get a WordPress User object instance so I can work with this customer.

                  $username   = $user->user_login;

                  file_put_contents(dirname(dirname( __FILE__)) . '/sharelog.txt', 'The following user has cancelled their subscription: '.$user_id.' - '.$username."\n", FILE_APPEND);
            }
      }
?>

Now if I go to the URL http://xxx.xx.xxx.xx/~xxxx/pilates/?secretKey=mdg4s6hj6dfs4g&user_id=32 then it works, I get the written entry in the log file saying that my user (id and username) has been cancelled.
But if I use the cancellation form, it doesn’t work.

How about this?

function kts_user_role_update_email( $user_id, $new_role, $old_role ) {
	$user_info = get_userdata( $user_id );
	
	if ( !empty( $old_role ) && $new_role == 'subscriber' ) {
		if($_GET['secretKey'] === 'mdg4s6hj6dfs4g') {
			
			file_put_contents(dirname(dirname( __FILE__)) . '/sharelog.txt', 'The following user has cancelled their subscription: '.$user_id.' - '.$username."\n", FILE_APPEND);
		}
    }
}
add_action( 'set_user_role', 'kts_user_role_update_email', 10, 3);