Skip to content

Instantly share code, notes, and snippets.

@danieliser
Created November 3, 2022 22:41
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save danieliser/1a8837af4b8effa4accae18512c4a268 to your computer and use it in GitHub Desktop.
Save danieliser/1a8837af4b8effa4accae18512c4a268 to your computer and use it in GitHub Desktop.
EDD Subscription Cancellation UX using Gravity Forms & WP Fusion
<?php
/**
* Assumptions:
* - Form ID is #28
* - Page ID is 406200
* - Fields include radio for reason & extra details where needed.
*/
namespace CustomCode;
# Filter EDD sub cancellation link to custom page.
add_filter( 'edd_subscription_cancel_url', __NAMESPACE__ . '\\modify_edd_subscription_cancel_url', 10, 2 );
# During template redirect check if the user is trying to cancel a valid subscription of theirs.
add_action( 'template_redirect', __NAMESPACE__ . '\\protect_subscription_cancellation_page' );
# Checks if validation for hidden field #3 fails, if so moves its error to the main top error spot.
add_filter( 'gform_validation_message_28', __NAMESPACE__ . '\\modify_error_message_locations_28', 10, 2 );
# Hook into gravity form validation for form #28, check that field #3 is a valid sub_id
add_filter( 'gform_field_validation_28_3', __NAMESPACE__ . '\\validate_sub_cancellation_sub_id', 10, 4 );
# After gravity form #28 submission, get sub_id from field 3, and use it to cancel easy digital downloads subscription
add_action( 'gform_after_submission_28', __NAMESPACE__ . '\\cancel_edd_subscription', 10, 2 );
# After submission, if user skipped survey, tag them for future follow up.
add_filter( 'wpf_gravity_forms_apply_tags_28', __NAMESPACE__ . '\\add_tags_for_users_without_survey_submission', 10, 4 );
/**
* Modify the cancel URL to go to the custom cancel page
*
* @since 2022-11-03
*
* @param string $url
* @param EDD_Subscription $EDD_Subscription
*
* @return string URL pointing to the cancel page
*/
function modify_edd_subscription_cancel_url( $url, $EDD_Subscription = null ) {
$cancel_id = ( defined( 'IS_LOCAL_DEV' ) && IS_LOCAL_DEV ) ? 406200 : 406200;
$url = add_query_arg( array( 'sub_id' => $EDD_Subscription->id ), get_permalink( $cancel_id ) );
return $url;
}
/**
* Prevent access to the subscription without
*
* @since 2022-11-03
*/
function protect_subscription_cancellation_page() {
$cancel_page = 406200;
// If not the cancel page, we don't need to do anything.
if ( ! is_page( $cancel_page ) ) {
return;
}
// If no sub id redirect to subscriptions page.
if ( ! isset( $_GET['sub_id'] ) ) {
wp_safe_redirect( 'https://wppopupmaker.com/your-account/subscriptions/' );
}
// Get sub id from url.
$sub_id = absint( $_GET['sub_id'] );
$subscription = new \EDD_Subscription( $sub_id );
# Verify subscription is cancelable & by this user.
if ( ! $subscription->can_cancel() || (int) $subscription->customer->user_id !== (int) get_current_user_id() ) {
wp_die( sprintf( 'No subscription #%d was found for your account. Please go back and try again.', $sub_id ) );
}
}
/**
* Check if the hidden field has an error message, if ss, set that error as the main form error.
*
* @since 2022-11-03
*/
function modify_error_message_locations_28( $message, $form ) {
$has_other_error = false;
$custom_error_field = false;
foreach ( $form['fields'] as $field ) {
if ( ! $field->failed_validation ) {
continue;
}
if ( ( $field->visibility === 'hidden' || $field->get_input_type() === 'hidden' ) && $field->id === 3 ) {
$custom_error_field = $field;
} else {
$has_other_error = true;
}
}
if ( $custom_error_field && ! $has_other_error ) {
$message = sprintf( '<h2 class="gform_submission_error hide_summary"><span class="gform-icon gform-icon--close"></span>%s</h2>', $custom_error_field->validation_message );
}
return $message;
}
/**
* Validate the hidden sub_id field has a valid subscription ID and the current user can cancel it.
*
* @since 2022-11-03
*/
function validate_sub_cancellation_sub_id( $result, $value, $form, $field ) {
$subscription = new \EDD_Subscription( absint( $value ) );
# Verify subscription is cancelable
if ( ! $subscription->can_cancel() || (int) $subscription->customer->user_id !== (int) get_current_user_id() ) {
$result['is_valid'] = false;
$result['message'] = sprintf( 'No subscription #%d was found with your account. Please go back and try again.', absint( $value ) );
}
return $result;
}
/**
* Helper function for setting a static flag throughout the submission process.
*/
function submission_flagged( $set_flag = null ) {
static $flag = false;
if ( null !== $set_flag ) {
$flag = $set_flag;
}
return $flag;
}
/**
* Cancel subscription and add nots for customer reasons.
*
* @since 2022-11-03
*/
function cancel_edd_subscription( $entry, $form ) {
$sub_id = rgar( $entry, '3' );
$subscription = new \EDD_Subscription( absint( $sub_id ) );
# Verify subscription is cancelable & by this user.
if ( ! $subscription->can_cancel() || (int) $subscription->customer->user_id !== (int) get_current_user_id() ) {
wp_die( sprintf( 'No active subscription #%d was found for your account. Please go back and try again.', $sub_id ) );
}
$gateway = edd_recurring()->get_gateway_class( $subscription->gateway );
$can_edd_mark_cancelled = true;
// Try and cancel at the gateway.
if ( $gateway ) {
$can_edd_mark_cancelled = false;
$gateway_obj = new $gateway();
$can_edd_mark_cancelled = $gateway_obj->cancel( $subscription, true );
}
if ( ! $can_edd_mark_cancelled ) {
wp_die( sprintf( 'There was an error cancelling your subscription #%d. Please contact us for assistance.', $sub_id ) );
}
// Cancel in EDD.
$subscription->cancel();
# Prepare reasoning.
$reason = rgar( $entry, '4' );
// Depending on $reason type, generate note text.
switch( $reason ) {
case 'expensive':
$reason_note = __( 'User found it too expensive' );
$enjoyed = (bool) rgar( $entry, '4' );
if ( ! $enjoyed ) {
$reasoning = sanitize_text_field( rgar( $entry, '5') );
if ( ! empty( $reasoning ) ) {
$reason_note .= sprintf( __( ' and said: %s' ), $reasoning );
}
}
break;
case 'do-not-use':
$reason_note = __( 'User was no longer using the product' );
$reasoning = sanitize_text_field( rgar( $entry, '9') );
if ( ! empty( $reasoning ) ) {
$reason_note .= sprintf( __( ' and said: %s' ), $reasoning );
}
break;
case 'unhappy':
$reason_note = __( 'User was unhappy with the product' );
$reasoning = sanitize_text_field( rgar( $entry, '5') );
if ( ! empty( $reasoning ) ) {
$reason_note .= sprintf( __( ' and said: %s' ), $reasoning );
}
break;
case 'other':
$reason_note = __( 'User had other reasons' );
$reasoning = sanitize_text_field( rgar( $entry, '8') );
if ( ! empty( $reasoning ) ) {
$reason_note .= sprintf( __( ' and said: %s' ), $reasoning );
}
break;
default:
submission_flagged( true );
$reason_note = __( 'User did not provide a reason' );
break;
}
# Create formatted sub cancellation note.
$sub_cancel_note = sprintf( __( 'Cancellation Reason: %s' ), $reason_note );
# Add note to subscription.
$subscription->add_note( $sub_cancel_note );
# Get cancelled product name.
$product_name = edd_get_download_name( $subscription->product_id );
# Create formatted note for customer profile.
$customer_cancel_note = sprintf(
__( 'Subscription #<a href="%s">%d</a> for %s cancelled. %s' ),
admin_url( 'edit.php?post_type=download&page=edd-subscriptions&id=' . $subscription->id ),
$sub_id,
$product_name,
$sub_cancel_note
);
# Add customer note
$subscription->customer->add_note( $customer_cancel_note );
}
/**
* Tags users who did not fill out the survey in our CRM for follow up later.
*
* @since 2022-11-03
*/
function add_tags_for_users_without_survey_submission( $apply_tags, $user_id, $contact_id, $form_id ) {
if ( submission_flagged() ) {
$apply_tags[] = 'Skipped Subscription Cancellation Survey';
}
return $apply_tags;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment