'subscrpt_order',
'post_status' => $status,
'fields' => 'ids',
'meta_query' => array(
array(
'key' => '_subscrpt_product_id',
'value' => $product_id,
),
),
'author' => get_current_user_id(),
);
$posts = get_posts( $args );
return count( $posts ) > 0 ? $posts[0] : false;
}
/**
* Check if product trial exixts for an user.
*
* @param int $product_id Product ID.
*
* @return boolean
*/
public static function check_trial( int $product_id ): bool {
return ! self::subscription_exists( $product_id, array( 'expired', 'pending', 'active', 'on-hold', 'pe_cancelled', 'cancelled' ) );
}
/**
* Rewew when expired.
*
* @param int $subscription_id Subscription ID.
*/
public static function renew( int $subscription_id ) {
$trial = get_post_meta( $subscription_id, '_subscrpt_trial', true );
if ( null !== $trial ) {
update_post_meta( $subscription_id, '_subscrpt_trial', null );
}
do_action( 'subscrpt_when_product_expired', $subscription_id, true );
}
/**
* Get Subscriptions Histories
*
* @param int $order_id Order ID.
*/
public static function get_subscriptions_from_order( $order_id ) {
global $wpdb;
$table_name = $wpdb->prefix . 'subscrpt_order_relation';
$histories = $wpdb->get_results(
$wpdb->prepare(
// @phpcs:ignore
'SELECT * FROM %i WHERE order_id=%d',
array( $table_name, $order_id )
)
);
return $histories;
}
/**
* Get Subscriptions Histories
*
* @param int $order_item_id Order item ID.
*/
public static function get_subscription_from_order_item_id( $order_item_id ) {
global $wpdb;
$table_name = $wpdb->prefix . 'subscrpt_order_relation';
return $wpdb->get_row(
$wpdb->prepare(
// @phpcs:ignore
'SELECT * FROM %i WHERE order_item_id=%d',
array( $table_name, $order_item_id )
)
);
}
/**
* Format price with Subscription
*
* @param string $price Price.
* @param int $subscription_id Subscription ID.
* @param bool $display_trial True/False.
*
* @return string
*/
public static function format_price_with_subscription( $price, $subscription_id, $display_trial = false ) {
$order_id = get_post_meta( $subscription_id, '_subscrpt_order_id', true );
$order_item_id = get_post_meta( $subscription_id, '_subscrpt_order_item_id', true );
$item_meta = wc_get_order_item_meta( $order_item_id, '_subscrpt_meta', true );
$order = wc_get_order( $order_id );
$time = '1' === $item_meta['time'] ? null : $item_meta['time'] . ' ';
$type = self::get_typos( $item_meta['time'], $item_meta['type'] );
$formatted_price = wc_price(
$price,
array(
'currency' => $order->get_currency(),
)
) . ' / ' . $time . $type;
if ( $display_trial ) {
$trial = $item_meta['trial'];
$has_trial = isset( $item_meta['trial'] ) && strlen( $item_meta['trial'] ) > 2;
if ( $has_trial ) {
$trial_html = '
+ Got ' . $trial . ' free trial!';
$formatted_price .= $trial_html;
}
}
return apply_filters( 'subscrpt_format_price_with_subscription', $formatted_price, $price, $subscription_id );
}
/**
* Format price with order item
*
* @param string $price Price.
* @param int $item_id Item Id.
* @param bool $display_trial display trial?.
*
* @return string
*/
public static function format_price_with_order_item( $price, $item_id, $display_trial = false ) {
$order_id = wc_get_order_id_by_order_item_id( $item_id );
$order = wc_get_order( $order_id );
$item_meta = wc_get_order_item_meta( $item_id, '_subscrpt_meta', true );
if ( ! $item_meta || ! is_array( $item_meta ) ) {
return false;
}
$time = 1 === (int) $item_meta['time'] ? null : $item_meta['time'] . '-';
$type = self::get_typos( $item_meta['time'], $item_meta['type'] );
$formatted_price = wc_price(
$price,
array(
'currency' => $order->get_currency(),
)
) . ' / ' . $time . $type;
if ( $display_trial ) {
$trial = $item_meta['trial'];
$has_trial = isset( $item_meta['trial'] ) && strlen( $item_meta['trial'] ) > 2;
if ( $has_trial ) {
$trial_html = '
+ Got ' . $trial . ' free trial!';
$formatted_price .= $trial_html;
}
}
return apply_filters( 'subscrpt_format_price_with_subscription', $formatted_price, $price, $item_id );
}
/**
* Get total subscriptions by product ID.
*
* @param int $product_id Product ID.
* @param string | array $status Status.
*
* @return \WP_Post | false
*/
public static function get_total_subscriptions_from_product( int $product_id, $status = array( 'active', 'pending', 'expired', 'pe_cancelled', 'cancelled' ) ) {
$args = array(
'post_type' => 'subscrpt_order',
'post_status' => $status,
'fields' => 'ids',
'meta_query' => array(
array(
'key' => '_subscrpt_product_id',
'value' => $product_id,
),
),
);
$posts = get_posts( $args );
return count( $posts );
}
/**
* Process renewal on order.
*
* @param int $subscription_id Subscription Id.
* @param int $order_id Order Id.
* @param int $order_item_id Order Item Id.
*
* @return void
*/
public static function process_order_renewal( $subscription_id, $order_id, $order_item_id ) {
global $wpdb;
$history_table = $wpdb->prefix . 'subscrpt_order_relation';
$comment_id = wp_insert_comment(
array(
'comment_author' => 'Subscription for WooCommerce',
'comment_content' => sprintf(
// translators: order id.
__( 'The order %s has been created for the subscription', 'sdevs_subscrpt' ),
$order_id
),
'comment_post_ID' => $subscription_id,
'comment_type' => 'order_note',
)
);
update_comment_meta( $comment_id, '_subscrpt_activity', __( 'Renewal Order', 'sdevs_subscrpt' ) );
$wpdb->insert(
$history_table,
array(
'subscription_id' => $subscription_id,
'order_id' => $order_id,
'order_item_id' => $order_item_id,
'type' => 'renew',
)
);
}
/**
* Process new subscription on order.
*
* @param \WC_Order_Item $order_item Order Item.
* @param string $post_status status.
* @param \WC_Product $product Product.
*
* @return int
*/
public static function process_new_subscription_order( $order_item, $post_status, $product ) {
global $wpdb;
$history_table = $wpdb->prefix . 'subscrpt_order_relation';
$args = array(
'post_title' => 'Subscription',
'post_type' => 'subscrpt_order',
'post_status' => $post_status,
);
$subscription_id = wp_insert_post( $args );
wp_update_post(
array(
'ID' => $subscription_id,
'post_title' => "Subscription #{$subscription_id}",
)
);
$comment_id = wp_insert_comment(
array(
'comment_author' => 'Subscription for WooCommerce',
'comment_content' => sprintf(
// translators: Order Id.
__( 'Subscription successfully created. order is %s', 'sdevs_subscrpt' ),
$order_item->get_order_id()
),
'comment_post_ID' => $subscription_id,
'comment_type' => 'order_note',
)
);
update_comment_meta( $comment_id, '_subscrpt_activity', __( 'New Subscription', 'sdevs_subscrpt' ) );
update_post_meta( $subscription_id, '_subscrpt_product_id', $product->get_id() );
$wpdb->insert(
$history_table,
array(
'subscription_id' => $subscription_id,
'order_id' => $order_item->get_order_id(),
'order_item_id' => $order_item->get_id(),
'type' => 'new',
)
);
return $subscription_id;
}
/**
* Get recurrings items from cart items.
*
* @param array $cart_items Cart items.
*
* @return array
*/
public static function get_recurrs_for_cart( $cart_items ) {
$recurrs = array();
foreach ( $cart_items as $key => $cart_item ) {
$product = $cart_item['data'];
if ( $product->is_type( 'simple' ) && isset( $cart_item['subscription'] ) ) {
$cart_subscription = $cart_item['subscription'];
$type = $cart_subscription['type'];
$price_html = wc_price( $cart_subscription['per_cost'] * $cart_item['quantity'] ) . '/ ' . $type;
$recurrs[ $key ] = array(
'trial_status' => ! is_null( $cart_subscription['trial'] ),
'price_html' => $price_html,
'start_date' => self::start_date( $cart_subscription['trial'] ),
'next_date' => self::next_date( ( $cart_subscription['time'] ?? 1 ) . ' ' . $cart_subscription['type'], $cart_subscription['trial'] ),
'can_user_cancel' => $cart_item['data']->get_meta( '_subscrpt_user_cancel' ),
);
}
}
return apply_filters( 'subscrpt_cart_recurring_items', $recurrs, $cart_items );
}
/**
* Create renewal order when subscription expired. [wip]
*
* @param int $subscription_id Subscription ID.
* @throws \WC_Data_Exception Exception.
* @throws \Exception Exception.
*/
public static function create_renewal_order( $subscription_id ) {
$order_item_id = get_post_meta( $subscription_id, '_subscrpt_order_item_id', true );
$order_id = wc_get_order_id_by_order_item_id( $order_item_id );
$old_order = self::check_order_for_renewal( $order_id );
if ( ! $old_order ) {
return;
}
$order_item = $old_order->get_item( $order_item_id );
$subscription_price = get_post_meta( $subscription_id, '_subscrpt_price', true );
$product_args = array(
'name' => $order_item->get_name(),
'subtotal' => $subscription_price,
'total' => $subscription_price,
);
// creating new order.
$new_order_data = self::create_new_order_for_renewal( $old_order, $order_item, $product_args );
if ( ! $new_order_data ) {
return;
}
$new_order = $new_order_data['order'];
$new_order_item_id = $new_order_data['order_item_id'];
self::create_renewal_history( $subscription_id, $new_order->get_id(), $new_order_item_id );
update_post_meta( $subscription_id, '_subscrpt_order_id', $new_order->get_id() );
update_post_meta( $subscription_id, '_subscrpt_order_item_id', $new_order_item_id );
self::clone_order_metadata( $new_order, $old_order );
self::clone_stripe_metadata_for_renewal( $subscription_id, $old_order, $new_order );
$new_order->calculate_totals();
$new_order->save();
if ( ! is_admin() ) {
$message = 'Renewal Order(#' . $new_order->get_id() . ') Created.';
if ( $new_order->has_status( 'pending' ) ) {
$message .= 'Please Pay now';
}
wc_add_notice( $message, 'success' );
}
do_action( 'subscrpt_after_create_renew_order', $new_order, $old_order, $subscription_id, false );
}
/**
* Clone stripe metadata from old order.
*
* @param int $subscription_id Subscription Id.
* @param \WC_Order $old_order Old Order Object.
* @param \WC_Order $new_order New Order Object.
*
* @return void
*/
public static function clone_stripe_metadata_for_renewal( $subscription_id, $old_order, $new_order ) {
$is_auto_renew = get_post_meta( $subscription_id, '_subscrpt_auto_renew', true );
$stripe_enabled = ( 'stripe' === $old_order->get_payment_method() && in_array( $is_auto_renew, array( 1, '1' ), true ) && subscrpt_is_auto_renew_enabled() && '1' === get_option( 'subscrpt_stripe_auto_renew', '1' ) );
if ( $stripe_enabled ) {
$new_order->update_meta_data( '_stripe_customer_id', $old_order->get_meta( '_stripe_customer_id' ) );
$new_order->update_meta_data( '_stripe_source_id', $old_order->get_meta( '_stripe_source_id' ) );
$new_order->set_payment_method( $old_order->get_payment_method() );
$new_order->set_payment_method_title( $old_order->get_payment_method_title() );
}
}
/**
* Create history for renewal.
*
* @param int $subscription_id Subscription Id.
* @param int $new_order_id New Order Id.
* @param int $new_order_item_id New Order Item Id.
*
* @return void
*/
public static function create_renewal_history( $subscription_id, $new_order_id, $new_order_item_id ) {
global $wpdb;
$history_table = $wpdb->prefix . 'subscrpt_order_relation';
$wpdb->insert(
$history_table,
array(
'subscription_id' => $subscription_id,
'order_id' => $new_order_id,
'order_item_id' => $new_order_item_id,
'type' => 'renew',
)
);
$comment_id = wp_insert_comment(
array(
'comment_author' => 'Subscription for WooCommerce',
'comment_content' => sprintf( 'Subscription Renewal order successfully created. order is %s', $new_order_id ),
'comment_post_ID' => $subscription_id,
'comment_type' => 'order_note',
)
);
update_comment_meta( $comment_id, '_subscrpt_activity', 'Renewal Order' );
}
/**
* Create new order for renewal.
*
* @param \WC_Order $old_order Old Order Object.
* @param \WC_Order_Item $order_item Old Order Item Object.
* @param array $product_args Product args for add product.
*
* @return array|false
*/
public static function create_new_order_for_renewal( \WC_Order $old_order, \WC_Order_Item $order_item, array $product_args ) {
$product = $order_item->get_product();
$user_id = $old_order->get_user_id();
$new_order = wc_create_order(
array(
'customer_id' => $user_id,
'status' => 'pending',
)
);
$product_meta = apply_filters( 'subscrpt_renewal_item_meta', wc_get_order_item_meta( $order_item->get_id(), '_subscrpt_meta', true ), $product, $order_item );
$product_args = apply_filters( 'subscrpt_renewal_product_args', $product_args, $product, $order_item );
if ( ! $product_args ) {
return false;
}
$new_order_item_id = $new_order->add_product(
$product,
$order_item->get_quantity(),
$product_args
);
wc_update_order_item_meta(
$new_order_item_id,
'_subscrpt_meta',
array(
'time' => $product_meta['time'],
'type' => $product_meta['type'],
'trial' => null,
)
);
return array(
'order' => $new_order,
'order_item_id' => $new_order_item_id,
);
}
/**
* Check if old order is completed or deleted!
*
* @param mixed $old_order_id Old Order Id.
*
* @return \WC_Order|false
*/
public static function check_order_for_renewal( $old_order_id ) {
$old_order = wc_get_order( $old_order_id );
if ( ! $old_order || 'completed' !== $old_order->get_status() ) {
if ( ! is_admin() ) {
return wc_add_notice( __( 'Subscription renewal isn\'t possible due to previous order not completed or deletion.', 'sdevs_subscrpt' ), 'error' );
}
return false;
}
return $old_order;
}
/**
* Save meta-data from old order
*
* @param \WC_Order $new_order new order object.
* @param \WC_Order $old_order old order object.
*
* @return void
*/
public static function clone_order_metadata( $new_order, $old_order ) {
$new_order->set_customer_id( $old_order->get_customer_id() );
$new_order->set_currency( $old_order->get_currency() );
// 3 Add Billing Fields
$customer = new \WC_Customer( $old_order->get_customer_id() );
$new_order->set_billing_city( $customer->get_billing_city() );
$new_order->set_billing_state( $customer->get_billing_state() );
$new_order->set_billing_postcode( $customer->get_billing_postcode() );
$new_order->set_billing_email( $customer->get_billing_email() );
$new_order->set_billing_phone( $customer->get_billing_phone() );
$new_order->set_billing_address_1( $customer->get_billing_address_1() );
$new_order->set_billing_address_2( $customer->get_billing_address_2() );
$new_order->set_billing_country( $customer->get_billing_country() );
$new_order->set_billing_first_name( $customer->get_billing_first_name() );
$new_order->set_billing_last_name( $customer->get_billing_last_name() );
$new_order->set_billing_company( $customer->get_billing_company() );
// 4 Add Shipping Fields
$new_order->set_shipping_country( $customer->get_shipping_country() );
$new_order->set_shipping_first_name( $customer->get_shipping_first_name() );
$new_order->set_shipping_last_name( $customer->get_shipping_last_name() );
$new_order->set_shipping_company( $customer->get_shipping_company() );
$new_order->set_shipping_address_1( $customer->get_shipping_address_1() );
$new_order->set_shipping_address_2( $customer->get_shipping_address_2() );
$new_order->set_shipping_city( $customer->get_shipping_city() );
$new_order->set_shipping_state( $customer->get_shipping_state() );
$new_order->set_shipping_postcode( $customer->get_shipping_postcode() );
}
}