get_all_by( $subscription->id, 'sub_id' );
include FrmTransLiteAppHelper::plugin_path() . '/views/subscriptions/sidebar_actions.php';
}
/**
* @since 6.5
*
* @param object $subscription
*
* @return void
*/
public static function show_receipt_link( $subscription ) {
$link = esc_html( $subscription->sub_id );
if ( $subscription->sub_id !== 'None' ) {
/**
* Filter a receipt link for a specific gateway.
* For example, Stripe uses frm_sub_stripe_receipt.
*
* @since 6.5
*
* @param string $link
*/
$link = apply_filters( 'frm_sub_' . $subscription->paysys . '_receipt', $link );
}
FrmAppHelper::kses_echo( $link, array( 'a' ) );
}
/**
* @param object $sub
* @param array $atts
*
* @return void
*/
public static function show_cancel_link( $sub, $atts = array() ) {
if ( ! isset( $sub->user_id ) ) {
global $wpdb;
$sub->user_id = $wpdb->get_var( $wpdb->prepare( 'SELECT user_id FROM ' . $wpdb->prefix . 'frm_items WHERE id=%d', $sub->item_id ) );
}
$link = self::cancel_link( $sub, $atts );
FrmTransLiteAppHelper::echo_confirmation_link( $link );
}
/**
* @param object $sub
* @param array $atts
*
* @return string
*/
public static function cancel_link( $sub, $atts = array() ) {
$defaults = array(
'cancel' => __( 'Cancel', 'formidable' ),
'canceled' => __( 'Canceled', 'formidable' ),
'confirm' => __( 'Are you sure you want to cancel that subscription?', 'formidable' ),
);
$atts = array_merge( $defaults, $atts );
if ( $sub->status === 'active' ) {
$link = admin_url( 'admin-ajax.php?action=frm_trans_cancel&sub=' . $sub->id . '&nonce=' . wp_create_nonce( 'frm_trans_ajax' ) );
$link = '';
$link .= esc_html( $atts['cancel'] );
$link .= '';
} else {
$link = esc_html( $atts['canceled'] );
}
return $link;
}
/**
* Handle routing to cancel a subscription.
*
* @return void
*/
public static function cancel_subscription() { // phpcs:ignore SlevomatCodingStandard.Complexity.Cognitive.ComplexityTooHigh
check_ajax_referer( 'frm_trans_ajax', 'nonce' );
FrmAppHelper::permission_check( 'frm_edit_entries' );
$canceled = false;
$sub_id = FrmAppHelper::get_param( 'sub', '', 'get', 'sanitize_text_field' );
if ( $sub_id ) {
$frm_sub = new FrmTransLiteSubscription();
$sub = $frm_sub->get_one( $sub_id );
if ( $sub ) {
$reason = '';
$debug_id = '';
switch ( $sub->paysys ) {
case 'stripe':
$canceled = FrmStrpLiteAppHelper::call_stripe_helper_class( 'cancel_subscription', $sub->sub_id );
break;
case 'square':
$canceled = FrmSquareLiteConnectHelper::cancel_subscription( $sub->sub_id );
break;
case 'paypal':
$response = FrmPayPalLiteConnectHelper::cancel_subscription( $sub->sub_id );
// Check for structured error response with message and debug_id (array or object)
$reason = '';
$debug_id = '';
$canceled = false !== $response;
if ( is_array( $response ) || is_object( $response ) ) {
// Extract error details without type checks to avoid Mago type narrowing
$response_array = is_array( $response ) ? $response : (array) $response;
$reason = $response_array['message'] ?? '';
// PayPal API returns debug_id (snake_case) in some cases and debugId (camelCase) in others
$debug_id = $response_array['debug_id'] ?? $response_array['debugId'] ?? '';
// If there's an error message or debug_id, the cancellation failed
if ( $reason || $debug_id ) {
$canceled = false;
}
} elseif ( false === $response ) {
// Response is false, get error from static properties
$reason = FrmPayPalLiteConnectHelper::get_latest_error_from_paypal_api();
$debug_id = FrmPayPalLiteConnectHelper::get_latest_debug_id_from_paypal_api();
$canceled = false;
}
break;
default:
$canceled = false;
break;
}//end switch
if ( $canceled ) {
self::change_subscription_status(
array(
'status' => 'future_cancel',
'sub' => $sub,
)
);
$message = __( 'Canceled', 'formidable' );
// phpcs:ignore Universal.ControlStructures.DisallowLonelyIf.Found
} else {
// If the reason is already a complete error message, use it directly
// instead of wrapping it redundantly in "Failed (...)"
if ( $reason && ! preg_match( '/^[A-Z_]+$/', $reason ) ) {
$message = $reason;
} else {
$message = __( 'Failed', 'formidable' );
if ( ! empty( $reason ) ) {
$message .= ' (' . $reason . ')';
}
}
}//end if
if ( $debug_id ) {
$message .= '
Debug ID: ' . esc_html( $debug_id );
}
} else {
$message = __( 'That subscription was not found', 'formidable' );
}//end if
} else {
$message = __( 'Oops! No subscription was selected for cancelation.', 'formidable' );
}//end if
wp_die(
sprintf(
'