woocommerce-subscriptions/includes/early-renewal/class-wcs-early-renewal-mod...

200 lines
7.3 KiB
PHP

<?php
/**
* A class to display and handle early renewal requests via the modal.
*
* @package WooCommerce Subscriptions
* @subpackage WCS_Early_Renewal
* @category Class
* @since 2.6.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
class WCS_Early_Renewal_Modal_Handler {
/**
* Attach callbacks.
*
* @since 2.6.0
*/
public static function init() {
add_action( 'woocommerce_subscription_details_table', array( __CLASS__, 'maybe_print_early_renewal_modal' ) );
add_action( 'wp_loaded', array( __CLASS__, 'process_early_renewal_request' ), 20 );
}
/**
* Prints the early renewal modal for a specific subscription. If eligible.
*
* @since 2.6.0
*
* @param WC_Subscription $subscription The subscription to print the modal for.
*/
public static function maybe_print_early_renewal_modal( $subscription ) {
if ( ! self::can_user_renew_early_via_modal( $subscription ) ) {
return;
}
$place_order_action = array(
'text' => __( 'Pay now', 'woocommerce-subscriptions' ),
'attributes' => array(
'id' => 'early_renewal_modal_submit',
'class' => 'button alt ',
'href' => add_query_arg( array(
'subscription_id' => $subscription->get_id(),
'process_early_renewal' => true,
'wcs_nonce' => wp_create_nonce( 'wcs-renew-early-modal-' . $subscription->get_id() ),
) ),
'data-payment-method' => $subscription->get_payment_method(),
),
);
$callback_args = array(
'callback' => array( __CLASS__, 'output_early_renewal_modal' ),
'parameters' => array( 'subscription' => $subscription ),
);
$modal = new WCS_Modal( $callback_args, '.subscription_renewal_early', 'callback', __( 'Renew early', 'woocommerce-subscriptions' ) );
$modal->add_action( $place_order_action );
$modal->print_html();
}
/**
* Prints the early renewal modal HTML.
*
* @since 2.6.0
* @param WC_Subscription $subscription The subscription to print the modal for.
*/
public static function output_early_renewal_modal( $subscription ) {
$totals = $subscription->get_order_item_totals();
$date_changes = WCS_Early_Renewal_Manager::get_dates_to_update( $subscription );
if ( isset( $totals['payment_method'] ) ) {
$totals['payment_method']['label'] = __( 'Payment:', 'woocommerce-subscriptions' );
}
// Convert the new next payment date into the site's timezone.
if ( ! empty( $date_changes['next_payment'] ) ) {
$new_next_payment_date = new WC_DateTime( $date_changes['next_payment'], new DateTimeZone( 'UTC' ) );
$new_next_payment_date->setTimezone( new DateTimeZone( wc_timezone_string() ) );
} else {
$new_next_payment_date = null;
}
wc_get_template(
'html-early-renewal-modal-content.php',
array(
'subscription' => $subscription,
'totals' => $totals,
'new_next_payment_date' => $new_next_payment_date,
),
'',
WC_Subscriptions_Plugin::instance()->get_plugin_directory( 'templates/' )
);
}
/**
* Processes the request to renew early via the modal.
*
* @since 2.6.0
*/
public static function process_early_renewal_request() {
if ( ! isset( $_GET['process_early_renewal'], $_GET['subscription_id'], $_GET['wcs_nonce'] ) ) {
return;
}
if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['wcs_nonce'] ) ), 'wcs-renew-early-modal-' . absint( $_GET['subscription_id'] ) ) ) {
wc_add_notice( __( 'There was an error with your request. Please try again.', 'woocommerce-subscriptions' ), 'error' );
self::redirect();
}
$subscription = wcs_get_subscription( absint( $_GET['subscription_id'] ) );
if ( ! $subscription ) {
wc_add_notice( __( 'We were unable to locate that subscription, please try again.', 'woocommerce-subscriptions' ), 'error' );
self::redirect();
}
if ( ! self::can_user_renew_early_via_modal( $subscription ) ) {
wc_add_notice( __( "You can't renew the subscription at this time. Please try again.", 'woocommerce-subscriptions' ), 'error' );
self::redirect();
}
// Before processing the request, detach the functions which handle standard renewal orders. Note we don't need to reattach them as this request will terminate soon.
self::detach_renewal_callbacks();
$renewal_order = wcs_create_renewal_order( $subscription );
if ( ! wcs_is_order( $renewal_order ) ) {
wc_add_notice( __( "We couldn't create a renewal order for your subscription, please try again.", 'woocommerce-subscriptions' ), 'error' );
self::redirect();
}
$renewal_order->set_payment_method( wc_get_payment_gateway_by_order( $subscription ) );
$renewal_order->update_meta_data( '_subscription_renewal_early', $subscription->get_id() );
$renewal_order->save();
// Attempt to collect payment with the subscription's current payment method.
WC_Subscriptions_Payment_Gateways::trigger_gateway_renewal_payment_hook( $renewal_order );
// Now that we've attempted to process the payment, refresh the order.
$renewal_order = wc_get_order( $renewal_order->get_id() );
// Failed early renewals won't place the subscription on-hold so delete unsuccessful early renewal orders and redirect the user to complete the payment via checkout.
if ( $renewal_order->needs_payment() ) {
$renewal_order->delete( true );
wc_add_notice( __( 'Payment for the renewal order was unsuccessful with your payment method on file, please try again.', 'woocommerce-subscriptions' ), 'error' );
wp_redirect( wcs_get_early_renewal_url( $subscription ) );
exit();
} else {
// Trigger the subscription payment complete hooks and reset suspension counts and user roles.
$subscription->payment_complete();
wcs_update_dates_after_early_renewal( $subscription, $renewal_order );
wc_add_notice( __( 'Your early renewal order was successful.', 'woocommerce-subscriptions' ), 'success' );
}
self::redirect();
}
/**
* Checks if a user can renew a subscription early via the modal window.
*
* @param int|WC_Subscription $subscription Post ID of a 'shop_subscription' post, or instance of a WC_Subscription object.
* @param int $user_id The ID of a user. Defaults to the current user.
* @return boolean
*
* @since 3.0.5
*/
public static function can_user_renew_early_via_modal( $subscription, $user_id = 0 ) {
$user_id = ! empty( $user_id ) ? absint( $user_id ) : get_current_user_id();
$subscription = wcs_get_subscription( $subscription );
if ( ! WCS_Early_Renewal_Manager::is_early_renewal_via_modal_enabled() || ! wcs_can_user_renew_early( $subscription, $user_id ) ) {
return false;
}
return apply_filters( 'woocommerce_subscriptions_can_user_renew_early_via_modal', $subscription->get_user_id() === $user_id, $subscription, $user_id );
}
/**
* Redirect the user after processing their early renewal request.
*
* @since 2.6.0
*/
private static function redirect() {
wp_redirect( remove_query_arg( array( 'process_early_renewal', 'subscription_id', 'wcs_nonce' ) ) );
exit();
}
/**
* Removes filters which shouldn't run while processing early renewals via the modal.
*
* @since 2.6.0
*/
private static function detach_renewal_callbacks() {
remove_filter( 'wcs_renewal_order_created', 'WC_Subscriptions_Renewal_Order::add_order_note', 10, 2 );
remove_filter( 'woocommerce_order_status_changed', 'WC_Subscriptions_Renewal_Order::maybe_record_subscription_payment', 10, 2 );
}
}