. * * @package WooCommerce Subscriptions * @author Prospress Inc. * @since 1.0 */ /** * Required functions */ if ( ! function_exists( 'woothemes_queue_update' ) || ! function_exists( 'is_woocommerce_active' ) ) { require_once( 'woo-includes/woo-functions.php' ); } /** * Plugin updates */ woothemes_queue_update( plugin_basename( __FILE__ ), '6115e6d7e297b623a169fdcf5728b224', '27147' ); /** * Check if WooCommerce is active and at the required minimum version, and if it isn't, disable Subscriptions. * * @since 1.0 */ if ( ! is_woocommerce_active() || version_compare( get_option( 'woocommerce_db_version' ), WC_Subscriptions::$wc_minimum_supported_version, '<' ) ) { add_action( 'admin_notices', 'WC_Subscriptions::woocommerce_inactive_notice' ); return; } define( 'WCS_INIT_TIMESTAMP', gmdate( 'U' ) ); require_once( 'wcs-functions.php' ); require_once( 'includes/class-wc-subscriptions-coupon.php' ); require_once( 'includes/class-wc-subscriptions-product.php' ); require_once( 'includes/admin/class-wc-subscriptions-admin.php' ); require_once( 'includes/class-wc-subscriptions-manager.php' ); require_once( 'includes/class-wc-subscriptions-cart.php' ); require_once( 'includes/class-wc-subscriptions-order.php' ); require_once( 'includes/class-wc-subscriptions-renewal-order.php' ); require_once( 'includes/class-wc-subscriptions-checkout.php' ); require_once( 'includes/class-wc-subscriptions-email.php' ); require_once( 'includes/class-wc-subscriptions-addresses.php' ); require_once( 'includes/class-wc-subscriptions-change-payment-gateway.php' ); require_once( 'includes/gateways/class-wc-subscriptions-payment-gateways.php' ); require_once( 'includes/gateways/paypal/class-wcs-paypal.php' ); require_once( 'includes/class-wc-subscriptions-switcher.php' ); require_once( 'includes/class-wc-subscriptions-synchroniser.php' ); require_once( 'includes/upgrades/class-wc-subscriptions-upgrader.php' ); require_once( 'includes/upgrades/class-wcs-upgrade-logger.php' ); require_once( 'includes/libraries/action-scheduler/action-scheduler.php' ); require_once( 'includes/abstracts/abstract-wcs-scheduler.php' ); require_once( 'includes/class-wcs-action-scheduler.php' ); require_once( 'includes/abstracts/abstract-wcs-cache-manager.php' ); require_once( 'includes/class-wcs-cached-data-manager.php' ); require_once( 'includes/class-wcs-post-meta-cache-manager.php' ); require_once( 'includes/class-wcs-post-meta-cache-manager-many-to-one.php' ); require_once( 'includes/class-wcs-cart-renewal.php' ); require_once( 'includes/class-wcs-cart-resubscribe.php' ); require_once( 'includes/class-wcs-cart-initial-payment.php' ); require_once( 'includes/class-wcs-download-handler.php' ); require_once( 'includes/class-wcs-retry-manager.php' ); require_once( 'includes/class-wcs-cart-switch.php' ); require_once( 'includes/class-wcs-limiter.php' ); require_once( 'includes/interfaces/interface-wcs-cache-updater.php' ); require_once( 'includes/abstracts/abstract-wcs-related-order-store.php' ); require_once( 'includes/data-stores/class-wcs-related-order-store-cpt.php' ); require_once( 'includes/data-stores/class-wcs-related-order-store-cached-cpt.php' ); require_once( 'includes/abstracts/abstract-wcs-customer-store.php' ); require_once( 'includes/data-stores/class-wcs-customer-store-cpt.php' ); require_once( 'includes/data-stores/class-wcs-customer-store-cached-cpt.php' ); require_once( 'includes/legacy/class-wcs-array-property-post-meta-black-magic.php' ); require_once( 'includes/class-wcs-failed-scheduled-action-manager.php' ); require_once( dirname( __FILE__ ) . '/includes/admin/class-wcs-admin-system-status.php' ); require_once( 'includes/abstracts/abstract-wcs-debug-tool.php' ); require_once( 'includes/abstracts/abstract-wcs-background-updater.php' ); require_once( 'includes/admin/debug-tools/class-wcs-debug-tool-factory.php' ); require_once( 'includes/admin/class-wcs-admin-notice.php' ); require_once( 'includes/upgrades/class-wcs-upgrade-notice-manager.php' ); require_once( 'includes/abstracts/abstract-wcs-background-upgrader.php' ); require_once( 'includes/class-wcs-staging.php' ); WCS_Admin_System_Status::init(); WCS_Upgrade_Notice_Manager::init(); WCS_Staging::init(); /** * The main subscriptions class. * * @since 1.0 */ class WC_Subscriptions { public static $name = 'subscription'; public static $activation_transient = 'woocommerce_subscriptions_activated'; public static $plugin_file = __FILE__; public static $version = '2.3.7'; public static $wc_minimum_supported_version = '2.6'; private static $total_subscription_count = null; private static $scheduler; /** @var WCS_Cache_Manager */ public static $cache; /** * Set up the class, including it's hooks & filters, when the file is loaded. * * @since 1.0 **/ public static function init() { // Register our custom subscription order type after WC_Post_types::register_post_types() add_action( 'init', __CLASS__ . '::register_order_types', 6 ); add_filter( 'woocommerce_data_stores', __CLASS__ . '::add_data_stores', 10, 1 ); // Register our custom subscription order statuses before WC_Post_types::register_post_status() add_action( 'init', __CLASS__ . '::register_post_status', 9 ); add_action( 'init', __CLASS__ . '::maybe_activate_woocommerce_subscriptions' ); register_deactivation_hook( __FILE__, __CLASS__ . '::deactivate_woocommerce_subscriptions' ); // Override the WC default "Add to Cart" text to "Sign Up Now" (in various places/templates) add_filter( 'woocommerce_order_button_text', __CLASS__ . '::order_button_text' ); add_action( 'woocommerce_subscription_add_to_cart', __CLASS__ . '::subscription_add_to_cart', 30 ); add_action( 'woocommerce_variable-subscription_add_to_cart', __CLASS__ . '::variable_subscription_add_to_cart', 30 ); add_action( 'wcopc_subscription_add_to_cart', __CLASS__ . '::wcopc_subscription_add_to_cart' ); // One Page Checkout compatibility // Ensure a subscription is never in the cart with products add_filter( 'woocommerce_add_to_cart_validation', __CLASS__ . '::maybe_empty_cart', 10, 5 ); // Enqueue front-end styles, run after Storefront because it sets the styles to be empty add_filter( 'woocommerce_enqueue_styles', __CLASS__ . '::enqueue_styles', 100, 1 ); // Load translation files add_action( 'init', __CLASS__ . '::load_plugin_textdomain', 3 ); // Load frontend scripts add_action( 'wp_enqueue_scripts', __CLASS__ . '::enqueue_frontend_scripts', 3 ); // Load dependent files add_action( 'plugins_loaded', __CLASS__ . '::load_dependant_classes' ); // Attach hooks which depend on WooCommerce constants add_action( 'plugins_loaded', __CLASS__ . '::attach_dependant_hooks' ); // Make sure the related order data store instance is loaded and initialised so that cache management will function add_action( 'plugins_loaded', 'WCS_Related_Order_Store::instance' ); // Make sure the related order data store instance is loaded and initialised so that cache management will function add_action( 'plugins_loaded', 'WCS_Customer_Store::instance' ); // Staging site or site migration notice add_action( 'admin_notices', __CLASS__ . '::woocommerce_site_change_notice' ); // Add the "Settings | Documentation" links on the Plugins administration screen add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), __CLASS__ . '::action_links' ); add_filter( 'action_scheduler_queue_runner_batch_size', __CLASS__ . '::action_scheduler_multisite_batch_size' ); add_action( 'in_plugin_update_message-' . plugin_basename( __FILE__ ), __CLASS__ . '::update_notice', 10, 2 ); // get details of orders of a customer add_action( 'wp_ajax_wcs_get_customer_orders', __CLASS__ . '::get_customer_orders' ); self::$cache = WCS_Cache_Manager::get_instance(); $scheduler_class = apply_filters( 'woocommerce_subscriptions_scheduler', 'WCS_Action_Scheduler' ); self::$scheduler = new $scheduler_class(); } /** * Get customer's order details via ajax. */ public static function get_customer_orders() { check_ajax_referer( 'get-customer-orders', 'security' ); if ( ! current_user_can( 'edit_shop_orders' ) ) { wp_die( -1 ); } $user_id = absint( $_POST['user_id'] ); $orders = wc_get_orders( array( 'customer' => $user_id, 'post_type' => 'shop_order', 'posts_per_page' => '-1' ) ); $customer_orders = array(); foreach ( $orders as $order ) { $customer_orders[ wcs_get_objects_property( $order, 'id' ) ] = $order->get_order_number(); } wp_send_json( $customer_orders ); } /** * Register data stores for WooCommerce 3.0+ * * @since 2.2.0 */ public static function add_data_stores( $data_stores ) { // Our custom data stores. $data_stores['subscription'] = 'WCS_Subscription_Data_Store_CPT'; $data_stores['product-variable-subscription'] = 'WCS_Product_Variable_Data_Store_CPT'; // Use WC core data stores for our products. $data_stores['product-subscription_variation'] = 'WC_Product_Variation_Data_Store_CPT'; $data_stores['order-item-line_item_pending_switch'] = 'WC_Order_Item_Product_Data_Store'; return $data_stores; } /** * Register core post types * * @since 2.0 */ public static function register_order_types() { wc_register_order_type( 'shop_subscription', apply_filters( 'woocommerce_register_post_type_subscription', array( // register_post_type() params 'labels' => array( 'name' => __( 'Subscriptions', 'woocommerce-subscriptions' ), 'singular_name' => __( 'Subscription', 'woocommerce-subscriptions' ), 'add_new' => _x( 'Add Subscription', 'custom post type setting', 'woocommerce-subscriptions' ), 'add_new_item' => _x( 'Add New Subscription', 'custom post type setting', 'woocommerce-subscriptions' ), 'edit' => _x( 'Edit', 'custom post type setting', 'woocommerce-subscriptions' ), 'edit_item' => _x( 'Edit Subscription', 'custom post type setting', 'woocommerce-subscriptions' ), 'new_item' => _x( 'New Subscription', 'custom post type setting', 'woocommerce-subscriptions' ), 'view' => _x( 'View Subscription', 'custom post type setting', 'woocommerce-subscriptions' ), 'view_item' => _x( 'View Subscription', 'custom post type setting', 'woocommerce-subscriptions' ), 'search_items' => __( 'Search Subscriptions', 'woocommerce-subscriptions' ), 'not_found' => self::get_not_found_text(), 'not_found_in_trash' => _x( 'No Subscriptions found in trash', 'custom post type setting', 'woocommerce-subscriptions' ), 'parent' => _x( 'Parent Subscriptions', 'custom post type setting', 'woocommerce-subscriptions' ), 'menu_name' => __( 'Subscriptions', 'woocommerce-subscriptions' ), ), 'description' => __( 'This is where subscriptions are stored.', 'woocommerce-subscriptions' ), 'public' => false, 'show_ui' => true, 'capability_type' => 'shop_order', 'map_meta_cap' => true, 'publicly_queryable' => false, 'exclude_from_search' => true, 'show_in_menu' => current_user_can( 'manage_woocommerce' ) ? 'woocommerce' : true, 'hierarchical' => false, 'show_in_nav_menus' => false, 'rewrite' => false, 'query_var' => false, 'supports' => array( 'title', 'comments', 'custom-fields' ), 'has_archive' => false, // wc_register_order_type() params 'exclude_from_orders_screen' => true, 'add_order_meta_boxes' => true, 'exclude_from_order_count' => true, 'exclude_from_order_views' => true, 'exclude_from_order_webhooks' => true, 'exclude_from_order_reports' => true, 'exclude_from_order_sales_reports' => true, 'class_name' => self::is_woocommerce_pre( '3.0' ) ? 'WC_Subscription_Legacy' : 'WC_Subscription', ) ) ); } /** * Method that returns the not found text. If the user has created at least one subscription, the standard message * will appear. If that's empty, the long, explanatory one will appear in the table. * * Filters: * - woocommerce_subscriptions_not_empty: gets passed the boolean option value. 'true' means the subscriptions * list is not empty, the user is familiar with how it works, and standard message appears. * - woocommerce_subscriptions_not_found_label: gets the original message for other plugins to modify, in case * they want to add more links, or modify any of the messages. * @since 2.0 * * @return string what appears in the list table of the subscriptions */ private static function get_not_found_text() { $subscriptions_exist = self::$cache->cache_and_get( 'wcs_do_subscriptions_exist', 'wcs_do_subscriptions_exist' ); if ( true === apply_filters( 'woocommerce_subscriptions_not_empty', $subscriptions_exist ) ) { $not_found_text = __( 'No Subscriptions found', 'woocommerce-subscriptions' ); } else { $not_found_text = '
' . __( 'Subscriptions will appear here for you to view and manage once purchased by a customer.', 'woocommerce-subscriptions' ) . '
'; // translators: placeholders are opening and closing link tags $not_found_text .= '' . sprintf( __( '%sLearn more about managing subscriptions »%s', 'woocommerce-subscriptions' ), '', '' ) . '
'; // translators: placeholders are opening and closing link tags $not_found_text .= '' . sprintf( __( '%sAdd a subscription product »%s', 'woocommerce-subscriptions' ), '', '' ) . '
'; } return apply_filters( 'woocommerce_subscriptions_not_found_label', $not_found_text ); } /** * Register our custom post statuses, used for order/subscription status */ public static function register_post_status() { $subscription_statuses = wcs_get_subscription_statuses(); $registered_statuses = apply_filters( 'woocommerce_subscriptions_registered_statuses', array( 'wc-active' => _nx_noop( 'Active (%s)', 'Active (%s)', 'post status label including post count', 'woocommerce-subscriptions' ), 'wc-switched' => _nx_noop( 'Switched (%s)', 'Switched (%s)', 'post status label including post count', 'woocommerce-subscriptions' ), 'wc-expired' => _nx_noop( 'Expired (%s)', 'Expired (%s)', 'post status label including post count', 'woocommerce-subscriptions' ), 'wc-pending-cancel' => _nx_noop( 'Pending Cancellation (%s)', 'Pending Cancellation (%s)', 'post status label including post count', 'woocommerce-subscriptions' ), ) ); if ( is_array( $subscription_statuses ) && is_array( $registered_statuses ) ) { foreach ( $registered_statuses as $status => $label_count ) { register_post_status( $status, array( 'label' => $subscription_statuses[ $status ], // use same label/translations as wcs_get_subscription_statuses() 'public' => false, 'exclude_from_search' => false, 'show_in_admin_all_list' => true, 'show_in_admin_status_list' => true, 'label_count' => $label_count, ) ); } } } /** * Enqueues scripts for frontend * * @since 2.3 */ public static function enqueue_frontend_scripts() { $dependencies = array( 'jquery' ); if ( is_cart() || is_checkout() ) { wp_enqueue_script( 'wcs-cart', plugin_dir_url( WC_Subscriptions::$plugin_file ) . 'assets/js/frontend/wcs-cart.js', $dependencies, WC_Subscriptions::$version, true ); } } /** * Enqueues stylesheet for the My Subscriptions table on the My Account page. * * @since 1.5 */ public static function enqueue_styles( $styles ) { if ( is_checkout() || is_cart() ) { $styles['wcs-checkout'] = array( 'src' => str_replace( array( 'http:', 'https:' ), '', plugin_dir_url( __FILE__ ) ) . 'assets/css/checkout.css', 'deps' => 'wc-checkout', 'version' => WC_VERSION, 'media' => 'all', ); } elseif ( is_account_page() ) { $styles['wcs-view-subscription'] = array( 'src' => str_replace( array( 'http:', 'https:' ), '', plugin_dir_url( __FILE__ ) ) . 'assets/css/view-subscription.css', 'deps' => 'woocommerce-smallscreen', 'version' => self::$version, 'media' => 'only screen and (max-width: ' . apply_filters( 'woocommerce_style_smallscreen_breakpoint', $breakpoint = '768px' ) . ')', ); } return $styles; } /** * Loads the my-subscriptions.php template on the My Account page. * * @since 1.0 * @param int $current_page */ public static function get_my_subscriptions_template( $current_page = 1 ) { $all_subscriptions = wcs_get_users_subscriptions(); $current_page = empty( $current_page ) ? 1 : absint( $current_page ); $posts_per_page = get_option( 'posts_per_page' ); $max_num_pages = ceil( count( $all_subscriptions ) / $posts_per_page ); $subscriptions = array_slice( $all_subscriptions, ( $current_page - 1 ) * $posts_per_page, $posts_per_page ); wc_get_template( 'myaccount/my-subscriptions.php', array( 'subscriptions' => $subscriptions, 'current_page' => $current_page, 'max_num_pages' => $max_num_pages, 'paginate' => true ), '', plugin_dir_path( __FILE__ ) . 'templates/' ); } /** * Output a redirect URL when an item is added to the cart when a subscription was already in the cart. * * @since 1.0 */ public static function redirect_ajax_add_to_cart( $fragments ) { $fragments['error'] = true; $fragments['product_url'] = wc_get_cart_url(); # Force error on add_to_cart() to redirect add_filter( 'woocommerce_add_to_cart_validation', '__return_false', 10 ); add_filter( 'woocommerce_cart_redirect_after_error', __CLASS__ . '::redirect_to_cart', 10, 2 ); do_action( 'wc_ajax_add_to_cart' ); return $fragments; } /** * Return a url for cart redirect. * * @since 2.3.0 */ public static function redirect_to_cart( $permalink, $product_id ) { return wc_get_cart_url(); } /** * When a subscription is added to the cart, remove other products/subscriptions to * work with PayPal Standard, which only accept one subscription per checkout. * * If multiple purchase flag is set, allow them to be added at the same time. * * @since 1.0 */ public static function maybe_empty_cart( $valid, $product_id, $quantity, $variation_id = '', $variations = array() ) { $is_subscription = WC_Subscriptions_Product::is_subscription( $product_id ); $cart_contains_subscription = WC_Subscriptions_Cart::cart_contains_subscription(); $multiple_subscriptions_possible = WC_Subscriptions_Payment_Gateways::one_gateway_supports( 'multiple_subscriptions' ); $manual_renewals_enabled = ( 'yes' == get_option( WC_Subscriptions_Admin::$option_prefix . '_accept_manual_renewals', 'no' ) ); $canonical_product_id = ! empty( $variation_id ) ? $variation_id : $product_id; if ( $is_subscription && 'yes' != get_option( WC_Subscriptions_Admin::$option_prefix . '_multiple_purchase', 'no' ) ) { // Generate a cart item key from variation and cart item data - which may be added by other plugins $cart_item_data = (array) apply_filters( 'woocommerce_add_cart_item_data', array(), $product_id, $variation_id ); $cart_item_id = WC()->cart->generate_cart_id( $product_id, $variation_id, $variations, $cart_item_data ); $product = wc_get_product( $product_id ); // If the product is sold individually or if the cart doesn't already contain this product, empty the cart. if ( ( $product && $product->is_sold_individually() ) || ! WC()->cart->find_product_in_cart( $cart_item_id ) ) { WC()->cart->empty_cart(); } } elseif ( $is_subscription && wcs_cart_contains_renewal() && ! $multiple_subscriptions_possible && ! $manual_renewals_enabled ) { self::remove_subscriptions_from_cart(); wc_add_notice( __( 'A subscription renewal has been removed from your cart. Multiple subscriptions can not be purchased at the same time.', 'woocommerce-subscriptions' ), 'notice' ); } elseif ( $is_subscription && $cart_contains_subscription && ! $multiple_subscriptions_possible && ! $manual_renewals_enabled && ! WC_Subscriptions_Cart::cart_contains_product( $canonical_product_id ) ) { self::remove_subscriptions_from_cart(); wc_add_notice( __( 'A subscription has been removed from your cart. Due to payment gateway restrictions, different subscription products can not be purchased at the same time.', 'woocommerce-subscriptions' ), 'notice' ); } elseif ( $cart_contains_subscription && 'yes' != get_option( WC_Subscriptions_Admin::$option_prefix . '_multiple_purchase', 'no' ) ) { self::remove_subscriptions_from_cart(); wc_add_notice( __( 'A subscription has been removed from your cart. Products and subscriptions can not be purchased at the same time.', 'woocommerce-subscriptions' ), 'notice' ); // Redirect to cart page to remove subscription & notify shopper if ( self::is_woocommerce_pre( '3.0.8' ) ) { add_filter( 'add_to_cart_fragments', __CLASS__ . '::redirect_ajax_add_to_cart' ); } else { add_filter( 'woocommerce_add_to_cart_fragments', __CLASS__ . '::redirect_ajax_add_to_cart' ); } } return $valid; } /** * Removes all subscription products from the shopping cart. * * @since 1.0 */ public static function remove_subscriptions_from_cart() { foreach ( WC()->cart->cart_contents as $cart_item_key => $cart_item ) { if ( WC_Subscriptions_Product::is_subscription( $cart_item['data'] ) ) { WC()->cart->set_quantity( $cart_item_key, 0 ); } } } /** * For a smoother sign up process, tell WooCommerce to redirect the shopper immediately to * the checkout page after she clicks the "Sign Up Now" button * * Only enabled if multiple checkout is not enabled. * * @param string $url The cart redirect $url WooCommerce determined. * @since 1.0 */ public static function add_to_cart_redirect( $url ) { // If product is of the subscription type if ( isset( $_REQUEST['add-to-cart'] ) && is_numeric( $_REQUEST['add-to-cart'] ) && WC_Subscriptions_Product::is_subscription( (int) $_REQUEST['add-to-cart'] ) ) { // Redirect to checkout if mixed checkout is disabled if ( 'yes' != get_option( WC_Subscriptions_Admin::$option_prefix . '_multiple_purchase', 'no' ) ) { $quantity = isset( $_REQUEST['quantity'] ) ? $_REQUEST['quantity'] : 1; $product_id = $_REQUEST['add-to-cart']; $add_to_cart_notice = wc_add_to_cart_message( array( $product_id => $quantity ), true, true ); if ( wc_has_notice( $add_to_cart_notice ) ) { $notices = wc_get_notices(); $add_to_cart_notice_index = array_search( $add_to_cart_notice, $notices['success'] ); unset( $notices['success'][ $add_to_cart_notice_index ] ); wc_set_notices( $notices ); } $url = wc_get_checkout_url(); } } return $url; } /** * Override the WooCommerce "Place Order" text with "Sign Up Now" * * @since 1.0 */ public static function order_button_text( $button_text ) { global $product; if ( WC_Subscriptions_Cart::cart_contains_subscription() ) { $button_text = get_option( WC_Subscriptions_Admin::$option_prefix . '_order_button_text', __( 'Sign Up Now', 'woocommerce-subscriptions' ) ); } return $button_text; } /** * Load the subscription add_to_cart template. * * Use the same cart template for subscription as that which is used for simple products. Reduce code duplication * and is made possible by the friendly actions & filters found through WC. * * Not using a custom template both prevents code duplication and helps future proof this extension from core changes. * * @since 1.0 */ public static function subscription_add_to_cart() { wc_get_template( 'single-product/add-to-cart/subscription.php', array(), '', plugin_dir_path( __FILE__ ) . 'templates/' ); } /** * Load the variable subscription add_to_cart template * * Use a very similar cart template as that of a variable product with added functionality. * * @since 2.0.9 */ public static function variable_subscription_add_to_cart() { global $product; // Enqueue variation scripts wp_enqueue_script( 'wc-add-to-cart-variation' ); // Get Available variations? $get_variations = sizeof( $product->get_children() ) <= apply_filters( 'woocommerce_ajax_variation_threshold', 30, $product ); // Load the template wc_get_template( 'single-product/add-to-cart/variable-subscription.php', array( 'available_variations' => $get_variations ? $product->get_available_variations() : false, 'attributes' => $product->get_variation_attributes(), 'selected_attributes' => $product->get_default_attributes(), ), '', plugin_dir_path( __FILE__ ) . 'templates/' ); } /** * Compatibility with WooCommerce On One Page Checkout. * * Use OPC's simple add to cart template for simple subscription products (to ensure data attributes required by OPC are added). * * Variable subscription products will be handled automatically because they identify as "variable" in response to is_type() method calls, * which OPC uses. * * @since 1.5.16 */ public static function wcopc_subscription_add_to_cart() { global $product; wc_get_template( 'checkout/add-to-cart/simple.php', array( 'product' => $product ), '', PP_One_Page_Checkout::$template_path ); } /** * Takes a number and returns the number with its relevant suffix appended, eg. for 2, the function returns 2nd * * @since 1.0 */ public static function append_numeral_suffix( $number ) { // Handle teens: if the tens digit of a number is 1, then write "th" after the number. For example: 11th, 13th, 19th, 112th, 9311th. http://en.wikipedia.org/wiki/English_numerals if ( strlen( $number ) > 1 && 1 == substr( $number, -2, 1 ) ) { // translators: placeholder is a number, this is for the teens $number_string = sprintf( __( '%sth', 'woocommerce-subscriptions' ), $number ); } else { // Append relevant suffix switch ( substr( $number, -1 ) ) { case 1: // translators: placeholder is a number, numbers ending in 1 $number_string = sprintf( __( '%sst', 'woocommerce-subscriptions' ), $number ); break; case 2: // translators: placeholder is a number, numbers ending in 2 $number_string = sprintf( __( '%snd', 'woocommerce-subscriptions' ), $number ); break; case 3: // translators: placeholder is a number, numbers ending in 3 $number_string = sprintf( __( '%srd', 'woocommerce-subscriptions' ), $number ); break; default: // translators: placeholder is a number, numbers ending in 4-9, 0 $number_string = sprintf( __( '%sth', 'woocommerce-subscriptions' ), $number ); break; } } return apply_filters( 'woocommerce_numeral_suffix', $number_string, $number ); } /* * Plugin House Keeping */ /** * Called when WooCommerce is inactive or running and out-of-date version to display an inactive notice. * * @since 1.2 */ public static function woocommerce_inactive_notice() { if ( current_user_can( 'activate_plugins' ) ) { $admin_notice_content = ''; if ( ! is_woocommerce_active() ) { $install_url = wp_nonce_url( add_query_arg( array( 'action' => 'install-plugin', 'plugin' => 'woocommerce' ), admin_url( 'update.php' ) ), 'install-plugin_woocommerce' ); // translators: 1$-2$: opening and closing tags, 3$-4$: link tags, takes to woocommerce plugin on wp.org, 5$-6$: opening and closing link tags, leads to plugins.php in admin $admin_notice_content = sprintf( esc_html__( '%1$sWooCommerce Subscriptions is inactive.%2$s The %3$sWooCommerce plugin%4$s must be active for WooCommerce Subscriptions to work. Please %5$sinstall & activate WooCommerce »%6$s', 'woocommerce-subscriptions' ), '', '', '', '', '', '' ); } elseif ( version_compare( get_option( 'woocommerce_db_version' ), self::$wc_minimum_supported_version, '<' ) ) { // translators: 1$-2$: opening and closing tags, 3$: minimum supported WooCommerce version, 4$-5$: opening and closing link tags, leads to plugin admin $admin_notice_content = sprintf( esc_html__( '%1$sWooCommerce Subscriptions is inactive.%2$s This version of Subscriptions requires WooCommerce %3$s or newer. Please %4$supdate WooCommerce to version %3$s or newer »%5$s', 'woocommerce-subscriptions' ), '', '', self::$wc_minimum_supported_version,'', '' ); } if ( $admin_notice_content ) { require_once( 'includes/admin/class-wcs-admin-notice.php' ); $notice = new WCS_Admin_Notice( 'error' ); $notice->set_simple_content( $admin_notice_content ); $notice->display(); } } } /** * Checks on each admin page load if Subscriptions plugin is activated. * * Apparently the official WP API is "lame" and it's far better to use an upgrade routine fired on admin_init: http://core.trac.wordpress.org/ticket/14170 * * @since 1.1 */ public static function maybe_activate_woocommerce_subscriptions() { $is_active = get_option( WC_Subscriptions_Admin::$option_prefix . '_is_active', false ); if ( false == $is_active ) { // Add the "Subscriptions" product type if ( ! get_term_by( 'slug', self::$name, 'product_type' ) ) { wp_insert_term( self::$name, 'product_type' ); } // Maybe add the "Variable Subscriptions" product type if ( ! get_term_by( 'slug', 'variable-subscription', 'product_type' ) ) { wp_insert_term( __( 'Variable Subscription', 'woocommerce-subscriptions' ), 'product_type' ); } // If no Subscription settings exist, its the first activation, so add defaults if ( get_option( WC_Subscriptions_Admin::$option_prefix . '_cancelled_role', false ) == false ) { WC_Subscriptions_Admin::add_default_settings(); } // if this is the first time activating WooCommerce Subscription we want to enable PayPal debugging by default. if ( '0' == get_option( WC_Subscriptions_Admin::$option_prefix . '_previous_version', '0' ) && false == get_option( WC_Subscriptions_admin::$option_prefix . '_paypal_debugging_default_set', false ) ) { $paypal_settings = get_option( 'woocommerce_paypal_settings' ); $paypal_settings['debug'] = 'yes'; update_option( 'woocommerce_paypal_settings', $paypal_settings ); update_option( WC_Subscriptions_admin::$option_prefix . '_paypal_debugging_default_set', 'true' ); } add_option( WC_Subscriptions_Admin::$option_prefix . '_is_active', true ); set_transient( self::$activation_transient, true, 60 * 60 ); flush_rewrite_rules(); do_action( 'woocommerce_subscriptions_activated' ); } } /** * Called when the plugin is deactivated. Deletes the subscription product type and fires an action. * * @since 1.0 */ public static function deactivate_woocommerce_subscriptions() { delete_option( WC_Subscriptions_Admin::$option_prefix . '_is_active' ); flush_rewrite_rules(); do_action( 'woocommerce_subscriptions_deactivated' ); } /** * Called on plugins_loaded to load any translation files. * * @since 1.1 */ public static function load_plugin_textdomain() { $plugin_rel_path = apply_filters( 'woocommerce_subscriptions_translation_file_rel_path', dirname( plugin_basename( __FILE__ ) ) . '/languages' ); // Then check for a language file in /wp-content/plugins/woocommerce-subscriptions/languages/ (this will be overriden by any file already loaded) load_plugin_textdomain( 'woocommerce-subscriptions', false, $plugin_rel_path ); } /** * Loads classes that depend on WooCommerce base classes. * * @since 1.2.4 */ public static function load_dependant_classes() { require_once( 'includes/class-wc-subscription.php' ); require_once( 'includes/class-wc-product-subscription.php' ); require_once( 'includes/class-wc-product-subscription-variation.php' ); require_once( 'includes/class-wc-product-variable-subscription.php' ); require_once( 'includes/admin/class-wcs-admin-post-types.php' ); require_once( 'includes/admin/class-wcs-admin-meta-boxes.php' ); require_once( 'includes/admin/class-wcs-admin-reports.php' ); require_once( 'includes/admin/reports/class-wcs-report-cache-manager.php' ); require_once( 'includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php' ); require_once( 'includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php' ); require_once( 'includes/admin/meta-boxes/class-wcs-meta-box-subscription-schedule.php' ); require_once( 'includes/class-wcs-change-payment-method-admin.php' ); require_once( 'includes/class-wcs-webhooks.php' ); require_once( 'includes/class-wcs-auth.php' ); require_once( 'includes/class-wcs-api.php' ); require_once( 'includes/class-wcs-template-loader.php' ); require_once( 'includes/class-wcs-query.php' ); require_once( 'includes/class-wcs-remove-item.php' ); require_once( 'includes/class-wcs-user-change-status-handler.php' ); require_once( 'includes/class-wcs-my-account-payment-methods.php' ); if ( self::is_woocommerce_pre( '3.0' ) ) { require_once( 'includes/legacy/class-wc-subscription-legacy.php' ); require_once( 'includes/legacy/class-wcs-product-legacy.php' ); require_once( 'includes/legacy/class-wc-product-subscription-legacy.php' ); require_once( 'includes/legacy/class-wc-product-subscription-variation-legacy.php' ); require_once( 'includes/legacy/class-wc-product-variable-subscription-legacy.php' ); // Load WC_DateTime when it doesn't exist yet so we can use it for datetime handling consistently with WC 3.0+ if ( ! class_exists( 'WC_DateTime' ) ) { require_once( 'includes/libraries/class-wc-datetime.php' ); } } else { require_once( 'includes/class-wc-order-item-pending-switch.php' ); require_once( 'includes/data-stores/class-wcs-subscription-data-store-cpt.php' ); require_once( 'includes/deprecated/class-wcs-deprecated-filter-hooks.php' ); require_once( 'includes/data-stores/class-wcs-product-variable-data-store-cpt.php' ); } // Provide a hook to enable running deprecation handling for stores that might want to check for deprecated code if ( apply_filters( 'woocommerce_subscriptions_load_deprecation_handlers', false ) ) { require_once( 'includes/abstracts/abstract-wcs-hook-deprecator.php' ); require_once( 'includes/abstracts/abstract-wcs-dynamic-hook-deprecator.php' ); require_once( 'includes/deprecated/class-wcs-action-deprecator.php' ); require_once( 'includes/deprecated/class-wcs-filter-deprecator.php' ); require_once( 'includes/deprecated/class-wcs-dynamic-action-deprecator.php' ); require_once( 'includes/deprecated/class-wcs-dynamic-filter-deprecator.php' ); } if ( class_exists( 'WCS_Early_Renewal' ) ) { $notice = new WCS_Admin_Notice( 'error' ); $notice->set_simple_content( sprintf( __( '%1$sWarning!%2$s We can see the %1$sWooCommerce Subscriptions Early Renewal%2$s plugin is active. Version %3$s of %1$sWooCommerce Subscriptions%2$s comes with that plugin\'s functionality packaged into the core plugin. Please deactivate WooCommerce Subscriptions Early Renewal to avoid any conflicts.', 'woocommerce-subscriptions' ), '', '', self::$version ) ); $notice->set_actions( array( array( 'name' => __( 'Installed Plugins', 'woocommerce-subscriptions' ), 'url' => admin_url( 'plugins.php' ), ), ) ); $notice->display(); } else { require_once( dirname( __FILE__ ) . '/includes/early-renewal/class-wcs-early-renewal-manager.php' ); WCS_Early_Renewal_Manager::init(); if ( WCS_Early_Renewal_Manager::is_early_renewal_enabled() ) { require_once( dirname( __FILE__ ) . '/includes/early-renewal/class-wcs-cart-early-renewal.php' ); require_once( dirname( __FILE__ ) . '/includes/early-renewal/wcs-early-renewal-functions.php' ); new WCS_Cart_Early_Renewal(); } } $failed_scheduled_action_manager = new WCS_Failed_Scheduled_Action_Manager( new WC_Logger() ); $failed_scheduled_action_manager->init(); if ( class_exists( 'WC_Abstract_Privacy' ) ) { require_once( 'includes/privacy/class-wcs-privacy.php' ); require_once( 'includes/privacy/class-wcs-privacy-background-updater.php' ); new WCS_Privacy(); } } /** * Some hooks need to check for the version of WooCommerce, which we can only do after WooCommerce is loaded. * * @since 1.5.17 */ public static function attach_dependant_hooks() { // Redirect the user immediately to the checkout page after clicking "Sign Up Now" buttons to encourage immediate checkout add_filter( 'woocommerce_add_to_cart_redirect', __CLASS__ . '::add_to_cart_redirect' ); if ( self::is_woocommerce_pre( '2.6' ) ) { // Display Subscriptions on a User's account page add_action( 'woocommerce_before_my_account', __CLASS__ . '::get_my_subscriptions_template' ); } } /** * Displays a notice when Subscriptions is being run on a different site, like a staging or testing site. * * @since 1.3.8 */ public static function woocommerce_site_change_notice() { if ( self::is_duplicate_site() && current_user_can( 'manage_options' ) ) { if ( ! empty( $_REQUEST['_wcsnonce'] ) && wp_verify_nonce( $_REQUEST['_wcsnonce'], 'wcs_duplicate_site' ) && isset( $_GET['wc_subscription_duplicate_site'] ) ) { if ( 'update' === $_GET['wc_subscription_duplicate_site'] ) { WC_Subscriptions::set_duplicate_site_url_lock(); } elseif ( 'ignore' === $_GET['wc_subscription_duplicate_site'] ) { update_option( 'wcs_ignore_duplicate_siteurl_notice', self::get_current_sites_duplicate_lock() ); } wp_safe_redirect( remove_query_arg( array( 'wc_subscription_duplicate_site', '_wcsnonce' ) ) ); } elseif ( self::get_current_sites_duplicate_lock() !== get_option( 'wcs_ignore_duplicate_siteurl_notice' ) ) { ?>tags, 3$-4$: opening and closing link tags. Leads to duplicate site article on docs printf( esc_html__( 'It looks like this site has moved or is a duplicate site. %1$sWooCommerce Subscriptions%2$s has disabled automatic payments and subscription related emails on this site to prevent duplicate payments from a staging or test environment. %3$sLearn more »%4$s.', 'woocommerce-subscriptions' ), '', '', '', '' ); ?>