Last active
February 21, 2024 21:34
-
-
Save igorbenic/5700dc00398dc86b432364d3851b313b to your computer and use it in GitHub Desktop.
Selling Simple Products as WooCommerce Subscriptions - Parts of code from tutorials | Selling Simple Products as WooCommerce Subscriptions - Admin | https://www.ibenic.com/selling-simple-products-woocommerce-subscriptions-front | https://www.ibenic.com/selling-simple-products-woocommerce-subscriptions-admin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Simple_Product_Subscriptions; | |
class Cart { | |
/** | |
* Cart Hooks | |
*/ | |
public function hooks() { | |
// Hooks from before here.... | |
// Add scheme data to cart items that can be purchased on a recurring basis. | |
add_filter( 'woocommerce_add_cart_item_data', array( __CLASS__, 'add_cart_item_data' ), 10, 3 ); | |
// Load saved session data of cart items that can be purchased on a recurring basis. | |
add_filter( 'woocommerce_get_cart_item_from_session', array( __CLASS__, 'load_cart_item_data_from_session' ), 5, 2 ); | |
} | |
// Functions from before are here | |
/** | |
* Add scheme data to cart items that can be purchased on a recurring basis. | |
* | |
* @param array $cart_item | |
* @param int $product_id | |
* @param int $variation_id | |
* @return array | |
*/ | |
public static function add_cart_item_data( $cart_item, $product_id, $variation_id ) { | |
if ( isset( $_POST['sps'] ) ) { | |
$cart_item['sps'] = $_POST['sps']; | |
} | |
return $cart_item; | |
} | |
/** | |
* Load saved session data of cart items that can be pruchased on a recurring basis. | |
* | |
* @param array $cart_item | |
* @param array $item_session_values | |
* @return array | |
*/ | |
public static function load_cart_item_data_from_session( $cart_item, $item_session_values ) { | |
if ( isset( $item_session_values[ 'sps' ] ) ) { | |
$cart_item[ 'sps' ] = $item_session_values[ 'sps' ]; | |
} | |
return $cart_item; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Simple_Product_Subscriptions; | |
class Cart { | |
/** | |
* Cart Hooks | |
*/ | |
public function hooks() { | |
add_action( 'woocommerce_after_add_to_cart_button', array( __CLASS__, 'add_to_cart_button' ) ); | |
// Other code will go here as well. | |
} | |
/** | |
* @param \WC_Product $product | |
* | |
* @return bool | |
*/ | |
public static function has_subscription_option( $product ) { | |
return Product::get_subscription_interval( $product->get_id() ) && Product::get_subscription_period( $product->get_id() ) && Product::get_subscription_price( $product->get_id() ); | |
} | |
/** | |
* Show the Subscription Add to Cart | |
*/ | |
public static function add_to_cart_button() { | |
global $product; | |
if ( ! self::has_subscription_option($product) ) { | |
return; | |
} | |
$price = wc_price( Product::get_subscription_price($product->get_id()) ) . sprintf(esc_html__(' every %1$s', 'sps'), wcs_get_subscription_period_strings(Product::get_subscription_interval($product->get_id()), Product::get_subscription_period($product->get_id()))); | |
$data = Product::get_subscription_interval($product->get_id()) . '_' . Product::get_subscription_period($product->get_id()); | |
?> | |
<div> | |
Or | |
<br/> | |
<button data-sps="<?php echo esc_attr( $data ); ?>" type="submit" name="add-to-cart" data-product_id="<?php echo esc_attr( $product->get_id() ); ?>" value="<?php echo esc_attr( $product->get_id() ); ?>" class="add_to_cart_button button alt ajax_add_to_cart"><?php echo $price; ?></button> | |
</div> | |
<?php | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Simple_Product_Subscriptions; | |
class Cart { | |
/** | |
* Cart Hooks | |
*/ | |
public function hooks() { | |
// Hooks from before are here | |
// Inspect product-level/cart-level session data and apply subscription schemes to cart items as needed. | |
add_action( 'woocommerce_cart_loaded_from_session', array( __CLASS__, 'apply_subscriptions' ), 5 ); | |
// Inspect product-level/cart-level session data on add-to-cart and apply subscription schemes to cart items as needed. Then, recalculate totals. | |
add_action( 'woocommerce_add_to_cart', array( __CLASS__, 'apply_subscription_schemes_on_add_to_cart' ), 19, 6 ); | |
} | |
// Methods from before are here | |
/** | |
* Inspect product-level/cart-level session data and apply subscription schemes on cart items as needed. | |
* Then, recalculate totals. | |
* | |
* @return void | |
*/ | |
public static function apply_subscription_schemes_on_add_to_cart( $item_key, $product_id, $quantity, $variation_id, $variation, $item_data ) { | |
self::apply_subscriptions( WC()->cart ); | |
} | |
/** | |
* Inspect product-level/cart-level session data and apply subscription schemes to cart items as needed. | |
* | |
* @param \WC_Cart $cart | |
* @return void | |
*/ | |
public static function apply_subscriptions( $cart ) { | |
foreach ( $cart->cart_contents as $cart_item_key => $cart_item ) { | |
if ( isset( $cart_item['sps'] ) ) { | |
// Convert the product object to a subscription, if needed. | |
$cart->cart_contents[ $cart_item_key ] = self::apply_subscription( $cart->cart_contents[ $cart_item_key ] ); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Simple_Product_Subscriptions; | |
class Admin { | |
public function run() { | |
add_action( 'woocommerce_product_options_pricing', array( $this, 'display_subscription_options' ) ); | |
add_action( 'woocommerce_process_product_meta', array( $this, 'save' ), 99, 2 ); | |
} | |
// ... code for display_subscription_options before is here | |
/** | |
* Saving Subscription Prices | |
* | |
* @param $post_id | |
* @param $post | |
*/ | |
public function save( $post_id, $post ) { | |
if ( isset( $_POST['_sp_subscription_interval'] ) ) { | |
Product::set_subscription_interval( $post_id, sanitize_text_field( $_POST['_sp_subscription_interval'] ) ); | |
} | |
if ( isset( $_POST['_sp_subscription_period'\] ) ) { | |
Product::set_subscription_period( $post_id, sanitize_text_field( $_POST['_sp_subscription_period'] ) ); | |
} | |
if ( isset( $_POST['_sp_subscription_price'] ) ) { | |
Product::set_subscription_price( $post_id, sanitize_text_field( $_POST['_sp_subscription_price'] ) ); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Simple_Product_Subscriptions; | |
class Cart { | |
/** | |
* Cart Hooks | |
*/ | |
public function hooks() { | |
add_action( 'woocommerce_after_add_to_cart_button', array( __CLASS__, 'add_to_cart_button' ) ); | |
// Add scheme data to cart items that can be purchased on a recurring basis. | |
add_filter( 'woocommerce_add_cart_item_data', array( __CLASS__, 'add_cart_item_data' ), 10, 3 ); | |
// Load saved session data of cart items that can be purchased on a recurring basis. | |
add_filter( 'woocommerce_get_cart_item_from_session', array( __CLASS__, 'load_cart_item_data_from_session' ), 5, 2 ); | |
// Inspect product-level/cart-level session data and apply subscription schemes to cart items as needed. | |
add_action( 'woocommerce_cart_loaded_from_session', array( __CLASS__, 'apply_subscriptions' ), 5 ); | |
// Inspect product-level/cart-level session data on add-to-cart and apply subscription schemes to cart items as needed. Then, recalculate totals. | |
add_action( 'woocommerce_add_to_cart', array( __CLASS__, 'apply_subscription_schemes_on_add_to_cart' ), 19, 6 ); | |
// Allow WCS to recognize any product as a subscription. | |
add_filter( 'woocommerce_is_subscription', array( __CLASS__, 'filter_is_subscription' ), 10, 3 ); | |
add_filter( 'woocommerce_cart_item_price', array( __CLASS__, 'show_cart_item_subscription_options' ), 1000, 3 ); | |
} | |
/** | |
* @param \WC_Product $product | |
* | |
* @return bool | |
*/ | |
public static function has_subscription_option( $product ) { | |
return Product::get_subscription_interval( $product->get_id() ) && Product::get_subscription_period( $product->get_id() ) && Product::get_subscription_price( $product->get_id() ); | |
} | |
/** | |
* Show the Subscription Add to Cart | |
*/ | |
public static function add_to_cart_button() { | |
global $product; | |
if ( ! self::has_subscription_option($product) ) { | |
return; | |
} | |
$price = wc_price( Product::get_subscription_price($product->get_id()) ) . sprintf(esc_html__(' every %1$s', 'sps'), wcs_get_subscription_period_strings(Product::get_subscription_interval($product->get_id()), Product::get_subscription_period($product->get_id()))); | |
$data = Product::get_subscription_interval($product->get_id()) . '_' . Product::get_subscription_period($product->get_id()); | |
?> | |
<div> | |
Or | |
<br/> | |
<button data-sps="<?php echo esc_attr( $data ); ?>" type="submit" name="add-to-cart" data-product_id="<?php echo esc_attr( $product->get_id() ); ?>" value="<?php echo esc_attr( $product->get_id() ); ?>" class="add_to_cart_button button alt ajax_add_to_cart"><?php echo $price; ?></button> | |
</div> | |
<?php | |
} | |
/** | |
* Displays cart item options for purchasing a product once or creating a subscription from it. | |
* | |
* @param string $price | |
* @param array $cart_item | |
* @param string $cart_item_key | |
* @return string | |
*/ | |
public static function show_cart_item_subscription_options( $price, $cart_item, $cart_item_key ) { | |
$product = $cart_item[ 'data' ]; | |
$supports_args = array( | |
'cart_item' => $cart_item, | |
'cart_item_key' => $cart_item_key | |
); | |
$is_mini_cart = did_action( 'woocommerce_before_mini_cart' ) !== did_action( 'woocommerce_after_mini_cart' ); | |
// Only show options in cart. | |
if ( ! is_cart() || $is_mini_cart ) { | |
return $price; | |
} | |
if ( ! self::is_subscription( $product ) ) { | |
return $price; | |
} | |
// Grab bare price without subscription details. | |
remove_filter( 'woocommerce_cart_product_price', array( 'WC_Subscriptions_Cart', 'cart_product_price' ), 10, 2 ); | |
remove_filter( 'woocommerce_cart_item_price', array( __CLASS__, 'show_cart_item_subscription_options' ), 1000, 3 ); | |
$price = wc_price( Product::get_subscription_price( $product->get_id() ) ) . sprintf(esc_html__(' every %1$s', 'jg-toolbox'), wcs_get_subscription_period_strings($product->get_meta( '_subscription_period_interval', true ), $product->get_meta( '_subscription_period', true ))); | |
add_filter( 'woocommerce_cart_item_price', array( __CLASS__, 'show_cart_item_subscription_options' ), 1000, 3 ); | |
add_filter( 'woocommerce_cart_product_price', array( 'WC_Subscriptions_Cart', 'cart_product_price' ), 10, 2 ); | |
return $price; | |
} | |
/** | |
* Hooks onto 'woocommerce_is_subscription' to trick WCS into thinking it is dealing with a subscription-type product. | |
* | |
* @param boolean $is | |
* @param int $product_id | |
* @param \WC_Product $product | |
* @return boolean | |
*/ | |
public static function filter_is_subscription( $is, $product_id, $product ) { | |
if ( ! $product ) { | |
return $is; | |
} | |
if ( self::is_subscription( $product ) ) { | |
$is = true; | |
} | |
return $is; | |
} | |
/** | |
* Determines if a subscription scheme is set on the product object. | |
* | |
* @param \WC_Product $product Product object to check. | |
* @return boolean Result of check. | |
*/ | |
public static function is_subscription( $product ) { | |
return $product->get_meta( '_subscription_period', true ) && $product->get_meta( '_subscription_period_interval', true ); | |
} | |
/** | |
* Delete object meta in use by the application layer. | |
* Note that the subscription state of a product object: | |
* | |
* 1. Cannot be persisted in the DB. | |
* 2. Is lost when the object is saved. | |
* | |
* This is intended behavior. | |
* | |
* @param \WC_Product $product | |
*/ | |
public static function delete_runtime_meta( $product ) { | |
// Don't delete any subscription product-type meta :) | |
if ( ! self::is_subscription_product_type( $product ) ) { | |
$product->delete_meta_data( '_subscription_period' ); | |
$product->delete_meta_data( '_subscription_period_interval' ); | |
$product->delete_meta_data( '_subscription_price' ); | |
} | |
} | |
/** | |
* Checks a product object to determine if it is a WCS subscription-type product. | |
* | |
* @param \WC_Product $product Product object to check. | |
* @return boolean Result of check. | |
*/ | |
public static function is_subscription_product_type( $product ) { | |
return $product->is_type( array( 'subscription', 'subscription_variation', 'variable-subscription' ) ); | |
} | |
/** | |
* Add scheme data to cart items that can be purchased on a recurring basis. | |
* | |
* @param array $cart_item | |
* @param int $product_id | |
* @param int $variation_id | |
* @return array | |
*/ | |
public static function add_cart_item_data( $cart_item, $product_id, $variation_id ) { | |
if ( isset( $_POST['sps'] ) ) { | |
$cart_item['sps'] = $_POST['sps']; | |
} | |
return $cart_item; | |
} | |
/** | |
* Load saved session data of cart items that can be pruchased on a recurring basis. | |
* | |
* @param array $cart_item | |
* @param array $item_session_values | |
* @return array | |
*/ | |
public static function load_cart_item_data_from_session( $cart_item, $item_session_values ) { | |
if ( isset( $item_session_values[ 'sps' ] ) ) { | |
$cart_item[ 'sps' ] = $item_session_values[ 'sps' ]; | |
} | |
return $cart_item; | |
} | |
/** | |
* Inspect product-level/cart-level session data and apply subscription schemes on cart items as needed. | |
* Then, recalculate totals. | |
* | |
* @return void | |
*/ | |
public static function apply_subscription_schemes_on_add_to_cart( $item_key, $product_id, $quantity, $variation_id, $variation, $item_data ) { | |
self::apply_subscriptions( WC()->cart ); | |
} | |
/** | |
* Get Subscription Scheme | |
* | |
* @param $cart_item | |
* | |
* @return array|mixed | |
*/ | |
public static function get_subscription_scheme( $cart_item ) { | |
return isset( $cart_item[ 'sps' ] ) ? $cart_item[ 'sps' ] : array(); | |
} | |
/** | |
* Set the active subscription scheme. Key value should be: | |
* | |
* - string to activate a subscription scheme (valid key required); | |
* - false to indicate that the product is sold in a non-recurring manner; or | |
* - null to indicate that the susbcription state of the product is undefined. | |
* | |
* Note that the scheme set on the object may become invalid if 'set_subscription_schemes' or 'set_forced_subscription_scheme' are modified. | |
* | |
* @param \WC_Product $product Product object. | |
* @param string $key Identifier of subscription scheme to activate on object. | |
* @return boolean Action result. | |
*/ | |
public static function set_subscription_scheme( $product, $scheme ) { | |
$period_value = explode( '_', $scheme ); | |
$period = $period_value[1]; | |
$interval = $period_value[0]; | |
$product->add_meta_data( '_subscription_period', $period ); | |
$product->add_meta_data( '_subscription_period_interval', $interval ); | |
$product->add_meta_data( '_subscription_price', Product::get_subscription_price( $product->get_id() ) ); | |
return true; | |
} | |
/** | |
* Applies a saved subscription key to a cart item. | |
* | |
* @param array $cart_item | |
* @return array | |
*/ | |
public static function apply_subscription( $cart_item ) { | |
$scheme_to_apply = self::get_subscription_scheme( $cart_item ); | |
if ( $scheme_to_apply ) { | |
self::set_subscription_scheme( $cart_item['data'], $scheme_to_apply ); | |
$cart_item['data']->set_price(Product::get_subscription_price( $cart_item['data']->get_id() ) ); | |
} | |
return apply_filters( 'sps_cart_item', $cart_item ); | |
} | |
/** | |
* Inspect product-level/cart-level session data and apply subscription schemes to cart items as needed. | |
* | |
* @param \WC_Cart $cart | |
* @return void | |
*/ | |
public static function apply_subscriptions( $cart ) { | |
foreach ( $cart->cart_contents as $cart_item_key => $cart_item ) { | |
if ( isset( $cart_item['sps'] ) ) { | |
// Convert the product object to a subscription, if needed. | |
$cart->cart_contents[ $cart_item_key ] = self::apply_subscription( $cart->cart_contents[ $cart_item_key ] ); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Simple_Product_Subscriptions; | |
class Cart { | |
// Code from before | |
/** | |
* Determines if a subscription scheme is set on the product object. | |
* | |
* @param \WC_Product $product Product object to check. | |
* @return boolean Result of check. | |
*/ | |
public static function is_subscription( $product ) { | |
return $product->get_meta( '_subscription_period', true ) && $product->get_meta( '_subscription_period_interval', true ); | |
} | |
/** | |
* Get Subscription Scheme | |
* | |
* @param $cart_item | |
* | |
* @return array|mixed | |
*/ | |
public static function get_subscription_scheme( $cart_item ) { | |
return isset( $cart_item[ 'sps' ] ) ? $cart_item[ 'sps' ] : array(); | |
} | |
/** | |
* Set the active subscription scheme. Key value should be: | |
* | |
* - string to activate a subscription scheme (valid key required); | |
* - false to indicate that the product is sold in a non-recurring manner; or | |
* - null to indicate that the susbcription state of the product is undefined. | |
* | |
* Note that the scheme set on the object may become invalid if 'set_subscription_schemes' or 'set_forced_subscription_scheme' are modified. | |
* | |
* @param \WC_Product $product Product object. | |
* @param string $key Identifier of subscription scheme to activate on object. | |
* @return boolean Action result. | |
*/ | |
public static function set_subscription_scheme( $product, $scheme ) { | |
$period_value = explode( '_', $scheme ); | |
$period = $period_value[1]; | |
$interval = $period_value[0]; | |
$product->add_meta_data( '_subscription_period', $period ); | |
$product->add_meta_data( '_subscription_period_interval', $interval ); | |
$product->add_meta_data( '_subscription_price', Product::get_subscription_price( $product->get_id() ) ); | |
return true; | |
} | |
/** | |
* Applies a saved subscription key to a cart item. | |
* | |
* @param array $cart_item | |
* @return array | |
*/ | |
public static function apply_subscription( $cart_item ) { | |
$scheme_to_apply = self::get_subscription_scheme( $cart_item ); | |
if ( $scheme_to_apply ) { | |
self::set_subscription_scheme( $cart_item['data'], $scheme_to_apply ); | |
// Set the temporary price to Cart item Product that is used for calculating totals. | |
$cart_item['data']->set_price(Product::get_subscription_price( $cart_item['data']->get_id() ) ); | |
} | |
return apply_filters( 'sps_cart_item', $cart_item ); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Simple_Product_Subscriptions; | |
class Cart { | |
/** | |
* Cart Hooks | |
*/ | |
public function hooks() { | |
// Hooks from before... | |
// Allow WCS to recognize any product as a subscription. | |
add_filter( 'woocommerce_is_subscription', array( __CLASS__, 'filter_is_subscription' ), 10, 3 ); | |
add_filter( 'woocommerce_cart_item_price', array( __CLASS__, 'show_cart_item_subscription_options' ), 1000, 3 ); | |
} | |
// Methods from before... | |
/** | |
* Displays cart item options for purchasing a product once or creating a subscription from it. | |
* | |
* @param string $price | |
* @param array $cart_item | |
* @param string $cart_item_key | |
* @return string | |
*/ | |
public static function show_cart_item_subscription_options( $price, $cart_item, $cart_item_key ) { | |
$product = $cart_item[ 'data' ]; | |
$supports_args = array( | |
'cart_item' => $cart_item, | |
'cart_item_key' => $cart_item_key | |
); | |
$is_mini_cart = did_action( 'woocommerce_before_mini_cart' ) !== did_action( 'woocommerce_after_mini_cart' ); | |
// Only show options in cart. | |
if ( ! is_cart() || $is_mini_cart ) { | |
return $price; | |
} | |
if ( ! self::is_subscription( $product ) ) { | |
return $price; | |
} | |
// Grab bare price without subscription details. | |
remove_filter( 'woocommerce_cart_product_price', array( 'WC_Subscriptions_Cart', 'cart_product_price' ), 10, 2 ); | |
remove_filter( 'woocommerce_cart_item_price', array( __CLASS__, 'show_cart_item_subscription_options' ), 1000, 3 ); | |
$price = wc_price( Product::get_subscription_price( $product->get_id() ) ) . sprintf(esc_html__(' every %1$s', 'jg-toolbox'), wcs_get_subscription_period_strings($product->get_meta( '_subscription_period_interval', true ), $product->get_meta( '_subscription_period', true ))); | |
add_filter( 'woocommerce_cart_item_price', array( __CLASS__, 'show_cart_item_subscription_options' ), 1000, 3 ); | |
add_filter( 'woocommerce_cart_product_price', array( 'WC_Subscriptions_Cart', 'cart_product_price' ), 10, 2 ); | |
return $price; | |
} | |
/** | |
* Hooks onto 'woocommerce_is_subscription' to trick WCS into thinking it is dealing with a subscription-type product. | |
* | |
* @param boolean $is | |
* @param int $product_id | |
* @param \WC_Product $product | |
* @return boolean | |
*/ | |
public static function filter_is_subscription( $is, $product_id, $product ) { | |
if ( ! $product ) { | |
return $is; | |
} | |
if ( self::is_subscription( $product ) ) { | |
$is = true; | |
} | |
return $is; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment