plugin = $plugin;
}
/** Register admin and runtime behavior. */
public function register() {
add_action( 'admin_menu', array( $this, 'add_menu' ) );
add_action( 'admin_init', array( $this, 'register_settings' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_assets' ) );
add_action( 'add_meta_boxes_product', array( $this, 'add_product_meta_box' ) );
add_action( 'woocommerce_admin_process_product_object', array( $this, 'save_product_controls' ) );
add_filter( 'divi_powers_woo_profile_cart_definition', array( $this, 'filter_profile_cart_definition' ), 20, 2 );
add_filter( 'divi_powers_woo_profile_product_quantity', array( $this, 'filter_profile_product_quantity' ), 20, 4 );
add_filter( 'divi_powers_woo_profile_sync_product_quantity', array( $this, 'filter_sync_profile_product_quantity' ), 20, 5 );
add_filter( 'divi_powers_woo_profile_extra_diagnostics', array( $this, 'filter_profile_diagnostics' ), 20, 2 );
add_filter( 'woocommerce_payment_complete_order_status', array( $this, 'filter_payment_complete_status' ), 20, 3 );
/*
* woocommerce_checkout_order_processed fires before WooCommerce finishes
* its payment/no-payment branch. Completing the order there can leave the
* browser with an AJAX error even though the order was saved.
*/
add_action( 'woocommerce_payment_complete', array( $this, 'maybe_complete_zero_order_after_checkout' ), 999, 1 );
add_action( 'woocommerce_order_status_processing', array( $this, 'maybe_complete_processing_order' ), 999 );
add_action( 'woocommerce_order_status_changed', array( $this, 'maybe_add_completion_note' ), 30, 4 );
add_filter( 'woocommerce_is_sold_individually', array( $this, 'filter_sold_individually' ), 30, 2 );
add_action( 'woocommerce_before_calculate_totals', array( $this, 'normalize_cart_quantities' ), 30 );
add_filter( 'woocommerce_product_is_visible', array( $this, 'filter_product_visibility' ), 30, 2 );
add_filter( 'woocommerce_is_purchasable', array( $this, 'filter_repeat_purchase_purchasable' ), 30, 2 );
add_action( 'woocommerce_after_checkout_validation', array( $this, 'validate_repeat_purchases' ), 30, 2 );
add_action( 'template_redirect', array( $this, 'capture_buy_now_context' ), -30 );
add_filter( 'woocommerce_add_to_cart_redirect', array( $this, 'filter_add_to_cart_redirect' ), 40, 2 );
add_action( 'woocommerce_add_to_cart', array( $this, 'maybe_isolate_added_item' ), 40, 6 );
add_filter( 'woocommerce_checkout_registration_enabled', array( $this, 'filter_registration_enabled' ), 20 );
add_filter( 'woocommerce_checkout_registration_required', array( $this, 'filter_registration_required' ), 20 );
add_filter( 'woocommerce_checkout_posted_data', array( $this, 'filter_checkout_posted_data' ), 20 );
add_filter( 'woocommerce_order_button_text', array( $this, 'filter_order_button_text' ), 20 );
/*
* Free checkout utilities run late so they can safely resolve conflicts
* with payment and subscription plugins that alter WooCommerce defaults.
*/
add_filter( 'woocommerce_cart_needs_payment', array( $this, 'filter_cart_needs_payment' ), 9999, 2 );
add_filter( 'woocommerce_order_needs_payment', array( $this, 'filter_order_needs_payment' ), 9999, 3 );
add_filter( 'woocommerce_available_payment_gateways', array( $this, 'filter_free_checkout_gateways' ), 9999 );
add_filter( 'woocommerce_checkout_fields', array( $this, 'filter_free_checkout_fields' ), 50 );
/*
* Flexible Subscriptions exposes this filter for deciding whether a free
* subscription checkout must still collect a payment method.
*/
add_filter( 'fsub/cart/require_payment_on_trial', array( $this, 'filter_flexible_subscription_payment_requirement' ), 9999 );
add_action( 'wp_loaded', array( $this, 'capture_campaign_coupon' ), 5 );
add_action( 'template_redirect', array( $this, 'capture_campaign_coupon' ), -20 );
add_action( 'wp_loaded', array( $this, 'apply_pending_coupon' ), 40 );
add_action( 'template_redirect', array( $this, 'apply_pending_coupon' ), 0 );
add_action( 'woocommerce_add_to_cart', array( $this, 'apply_pending_coupon' ), 90 );
add_action( 'woocommerce_thankyou', array( $this, 'clear_buy_now_context' ), 100 );
add_filter( 'woocommerce_coupons_enabled', array( $this, 'filter_coupons_enabled' ), 30 );
}
/** Global defaults. */
public static function defaults() {
return array(
'auto_complete_virtual' => 0,
'auto_complete_downloadable' => 0,
'auto_complete_zero' => 0,
'automation_notes' => 1,
'free_checkout_no_payment' => 1,
'free_checkout_trim_billing' => 0,
'free_checkout_button_text' => 'Complete order',
'free_checkout_subscription_mode' => 'auto',
'direct_checkout' => 0,
'force_quantity_one' => 0,
'cart_isolation' => 0,
'account_behavior' => 'default',
'coupon_links' => 1,
'hide_coupon_after_apply' => 1,
'order_button_text' => '',
);
}
/** Normalized global settings. */
public function settings() {
$saved = get_option( self::OPTION_KEY, array() );
return wp_parse_args( $this->sanitize_settings( is_array( $saved ) ? $saved : array() ), self::defaults() );
}
public function add_menu() {
add_submenu_page(
'divi-powers',
__( 'Commerce Utilities', '5d-powers-for-divi' ),
__( 'Commerce Utilities', '5d-powers-for-divi' ),
'manage_options',
'divi-powers-commerce-utilities',
array( $this, 'render_page' )
);
}
public function register_settings() {
register_setting(
'divi_powers_commerce_utilities_group',
self::OPTION_KEY,
array(
'type' => 'array',
'sanitize_callback' => array( $this, 'sanitize_settings' ),
'default' => self::defaults(),
)
);
}
/** Sanitize global controls. */
public function sanitize_settings( $input ) {
$input = is_array( $input ) ? $input : array();
$account = isset( $input['account_behavior'] ) ? sanitize_key( $input['account_behavior'] ) : 'default';
if ( ! in_array( $account, array( 'default', 'guest', 'optional', 'required', 'auto' ), true ) ) {
$account = 'default';
}
$subscription_mode = isset( $input['free_checkout_subscription_mode'] ) ? sanitize_key( $input['free_checkout_subscription_mode'] ) : 'auto';
if ( ! in_array( $subscription_mode, array( 'auto', 'skip', 'require' ), true ) ) {
$subscription_mode = 'auto';
}
return array(
'auto_complete_virtual' => empty( $input['auto_complete_virtual'] ) ? 0 : 1,
'auto_complete_downloadable' => empty( $input['auto_complete_downloadable'] ) ? 0 : 1,
'auto_complete_zero' => empty( $input['auto_complete_zero'] ) ? 0 : 1,
'automation_notes' => empty( $input['automation_notes'] ) ? 0 : 1,
'free_checkout_no_payment' => empty( $input['free_checkout_no_payment'] ) ? 0 : 1,
'free_checkout_trim_billing' => empty( $input['free_checkout_trim_billing'] ) ? 0 : 1,
'free_checkout_button_text' => isset( $input['free_checkout_button_text'] ) ? substr( sanitize_text_field( $input['free_checkout_button_text'] ), 0, 80 ) : 'Complete order',
'free_checkout_subscription_mode' => $subscription_mode,
'direct_checkout' => empty( $input['direct_checkout'] ) ? 0 : 1,
'force_quantity_one' => empty( $input['force_quantity_one'] ) ? 0 : 1,
'cart_isolation' => empty( $input['cart_isolation'] ) ? 0 : 1,
'account_behavior' => $account,
'coupon_links' => empty( $input['coupon_links'] ) ? 0 : 1,
'hide_coupon_after_apply' => empty( $input['hide_coupon_after_apply'] ) ? 0 : 1,
'order_button_text' => isset( $input['order_button_text'] ) ? substr( sanitize_text_field( $input['order_button_text'] ), 0, 80 ) : '',
);
}
public function enqueue_admin_assets() {
$page = isset( $_GET['page'] ) ? sanitize_key( wp_unslash( $_GET['page'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
if ( 'divi-powers-commerce-utilities' !== $page ) {
return;
}
wp_enqueue_style( 'divi-powers-commerce-utilities', DIVI_POWERS_URL . 'assets/css/commerce-utilities.css', array(), DIVI_POWERS_VERSION );
wp_enqueue_script(
'divi-powers-commerce-utilities',
DIVI_POWERS_URL . 'assets/js/commerce-utilities.js',
array( 'wp-i18n' ),
DIVI_POWERS_VERSION,
true
);
wp_set_script_translations( 'divi-powers-commerce-utilities', '5d-powers-for-divi' );
}
/** Commerce Utilities workspace. */
public function render_page() {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
$settings = $this->settings();
$enabled = $this->runtime_enabled();
$woo = $this->woo_available();
$profiles = array_values( apply_filters( 'divi_powers_funnel_woo_profiles', array() ) );
$products = $this->get_buy_now_products();
?>
ID, self::PRODUCT_FUNNEL_ONLY_META, true );
$force_one = (bool) get_post_meta( $post->ID, self::PRODUCT_FORCE_ONE_META, true );
$repeat = (bool) get_post_meta( $post->ID, self::PRODUCT_REPEAT_META, true );
$completion = sanitize_key( (string) get_post_meta( $post->ID, self::PRODUCT_COMPLETE_META, true ) );
if ( ! in_array( $completion, array( 'inherit', 'include', 'exclude' ), true ) ) { $completion = 'inherit'; }
?>
get_id() );
if ( ! $id || ! current_user_can( 'edit_post', $id ) ) { return; }
$funnel_only = empty( $_POST['divi_powers_funnel_only'] ) ? 0 : 1;
$product->update_meta_data( self::PRODUCT_FUNNEL_ONLY_META, $funnel_only );
$product->update_meta_data( self::PRODUCT_FORCE_ONE_META, empty( $_POST['divi_powers_force_quantity_one'] ) ? 0 : 1 );
$product->update_meta_data( self::PRODUCT_REPEAT_META, empty( $_POST['divi_powers_prevent_repeat_purchase'] ) ? 0 : 1 );
$completion = isset( $_POST['divi_powers_auto_complete'] ) ? sanitize_key( wp_unslash( $_POST['divi_powers_auto_complete'] ) ) : 'inherit';
if ( ! in_array( $completion, array( 'inherit', 'include', 'exclude' ), true ) ) { $completion = 'inherit'; }
$product->update_meta_data( self::PRODUCT_COMPLETE_META, $completion );
if ( method_exists( $product, 'get_catalog_visibility' ) && method_exists( $product, 'set_catalog_visibility' ) ) {
$current = $product->get_catalog_visibility();
$previous = sanitize_key( (string) $product->get_meta( self::PRODUCT_PREVIOUS_VISIBILITY_META, true ) );
if ( $funnel_only ) {
if ( 'hidden' !== $current && ! $previous ) { $product->update_meta_data( self::PRODUCT_PREVIOUS_VISIBILITY_META, $current ); }
$product->set_catalog_visibility( 'hidden' );
} elseif ( $previous ) {
$product->set_catalog_visibility( in_array( $previous, array( 'visible', 'catalog', 'search', 'hidden' ), true ) ? $previous : 'visible' );
$product->delete_meta_data( self::PRODUCT_PREVIOUS_VISIBILITY_META );
}
}
}
/** Preserve a generated Buy Now selection across the clean-route redirect. */
public function capture_buy_now_context() {
if ( ! $this->runtime_enabled() || ! function_exists( 'WC' ) || ! WC() || ! WC()->session ) { return; }
if ( isset( $_GET['dp_order'], $_GET['key'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
WC()->session->__unset( self::BUY_NOW_PRODUCT_SESSION );
WC()->session->__unset( self::BUY_NOW_QUANTITY_SESSION );
return;
}
$route = get_query_var( 'dp_checkout_journey' );
$product_id = $this->request_buy_now_product_id( false );
if ( $product_id ) {
WC()->session->set( self::BUY_NOW_PRODUCT_SESSION, $product_id );
WC()->session->set( self::BUY_NOW_QUANTITY_SESSION, $this->request_buy_now_quantity( false ) );
} elseif ( $route ) {
WC()->session->__unset( self::BUY_NOW_PRODUCT_SESSION );
WC()->session->__unset( self::BUY_NOW_QUANTITY_SESSION );
}
}
public function clear_buy_now_context() {
if ( function_exists( 'WC' ) && WC() && WC()->session ) {
WC()->session->__unset( self::BUY_NOW_PRODUCT_SESSION );
WC()->session->__unset( self::BUY_NOW_QUANTITY_SESSION );
}
}
/** Make generated route links and journey isolation use one coherent cart definition. */
public function filter_profile_cart_definition( $definition, $profile ) {
if ( ! $this->runtime_enabled() || ! is_array( $definition ) || ! is_array( $profile ) ) { return $definition; }
$product_id = $this->request_buy_now_product_id();
$isolation = $this->effective_bool( 'cart_isolation', $profile );
if ( $product_id ) {
if ( $isolation ) {
$definition['product_ids'] = array( $product_id );
$definition['cart_behavior'] = 'replace';
} else {
$definition['product_ids'] = array_values( array_unique( array_merge( isset( $definition['product_ids'] ) ? $definition['product_ids'] : array(), array( $product_id ) ) ) );
if ( 'preserve' === ( $definition['cart_behavior'] ?? 'preserve' ) ) { $definition['cart_behavior'] = 'append'; }
}
} elseif ( $isolation && ! empty( $definition['product_ids'] ) ) {
$definition['cart_behavior'] = 'replace';
}
return $definition;
}
public function filter_profile_product_quantity( $quantity, $product_id, $profile, $definition ) {
$requested = $this->request_buy_now_quantity();
if ( ! $requested ) { $requested = absint( $quantity ); }
$requested = max( 1, min( 99, $requested ? $requested : 1 ) );
$product = function_exists( 'wc_get_product' ) ? wc_get_product( absint( $product_id ) ) : null;
if ( ( $product && $this->product_force_one( $product ) ) || $this->effective_bool( 'force_quantity_one', is_array( $profile ) ? $profile : null ) ) { return 1; }
return $requested;
}
public function filter_sync_profile_product_quantity( $sync, $product_id, $quantity, $profile, $definition ) {
return absint( $this->request_buy_now_product_id() ) === absint( $product_id ) ? true : $sync;
}
public function filter_profile_diagnostics( $issues, $definition ) {
$issues = is_array( $issues ) ? $issues : array();
if ( ! $this->plugin->is_power_enabled( 'commerce_utilities' ) ) { return $issues; }
$profile = array( 'definition' => is_array( $definition ) ? $definition : array() );
if ( $this->effective_bool( 'cart_isolation', $profile ) && empty( $definition['product_ids'] ) ) {
$issues[] = array( 'severity' => 'warning', 'code' => 'commerce_isolation_products', 'message' => __( 'Commerce cart isolation is enabled, but this profile has no assigned products. Use a generated Buy Now link with a product or assign the dedicated offer products.', '5d-powers-for-divi' ) );
}
return $issues;
}
/** Determine final order status immediately after confirmed payment. */
public function filter_payment_complete_status( $status, $order_id, $order ) {
if ( ! $this->runtime_enabled() || 'completed' === $status || ! $this->order_is_eligible_for_completion( $order, false ) ) { return $status; }
if ( is_object( $order ) && method_exists( $order, 'update_meta_data' ) ) {
$order->update_meta_data( self::AUTO_COMPLETE_REASON_META, 'paid-digital' );
$order->save_meta_data();
}
return 'completed';
}
/**
* Complete eligible non-recurring free digital orders only after
* WooCommerce has finished its payment/no-payment processing.
*/
public function maybe_complete_zero_order_after_checkout( $order_id ) {
if ( ! $this->runtime_enabled() || ! function_exists( 'wc_get_order' ) ) { return; }
$order = wc_get_order( $order_id );
if ( ! $order || (float) $order->get_total() > 0 || ! $this->order_is_eligible_for_completion( $order, true ) ) { return; }
$status = $order->get_status();
if ( in_array( $status, array( 'pending', 'processing' ), true ) ) {
$order->update_meta_data( self::AUTO_COMPLETE_REASON_META, 'zero-total-digital' );
$order->save_meta_data();
$order->update_status( 'completed' );
}
}
public function maybe_complete_processing_order( $order_id ) {
if ( ! $this->runtime_enabled() || ! function_exists( 'wc_get_order' ) ) { return; }
$order = wc_get_order( $order_id );
if ( ! $order || 'processing' !== $order->get_status() || ! $order->is_paid() || ! $this->order_is_eligible_for_completion( $order, false ) ) { return; }
$order->update_meta_data( self::AUTO_COMPLETE_REASON_META, 'paid-digital' );
$order->save_meta_data();
$order->update_status( 'completed' );
}
public function maybe_add_completion_note( $order_id, $from, $to, $order ) {
if ( 'completed' !== $to || ! is_object( $order ) || ! method_exists( $order, 'get_meta' ) ) { return; }
$reason = sanitize_key( (string) $order->get_meta( self::AUTO_COMPLETE_REASON_META, true ) );
if ( ! $reason || $order->get_meta( self::AUTO_COMPLETE_NOTE_META, true ) ) { return; }
$profile = $this->profile_for_order( $order );
if ( $this->effective_bool( 'automation_notes', $profile ) && method_exists( $order, 'add_order_note' ) ) {
$message = 'zero-total-digital' === $reason
? __( '5D Powers for Divi automatically completed this zero-total digital order.', '5d-powers-for-divi' )
: __( '5D Powers for Divi automatically completed this paid digital order after payment was confirmed.', '5d-powers-for-divi' );
$order->add_order_note( $message );
}
$order->update_meta_data( self::AUTO_COMPLETE_NOTE_META, 1 );
$order->save_meta_data();
}
private function order_is_eligible_for_completion( $order, $zero_total ) {
if ( ! is_object( $order ) || ! method_exists( $order, 'get_items' ) ) { return false; }
$status = method_exists( $order, 'get_status' ) ? $order->get_status() : '';
if ( in_array( $status, array( 'on-hold', 'failed', 'cancelled', 'refunded', 'trash' ), true ) ) { return false; }
if ( $zero_total ) {
if ( (float) $order->get_total() > 0 || ! $this->effective_bool( 'auto_complete_zero', $this->profile_for_order( $order ) ) ) { return false; }
} elseif ( ! method_exists( $order, 'is_paid' ) || ! $order->is_paid() ) {
return false;
}
if ( $this->order_has_incompatible_fulfillment( $order ) ) { return false; }
$profile = $this->profile_for_order( $order );
$allow_virtual = $this->effective_bool( 'auto_complete_virtual', $profile );
$allow_downloadable = $this->effective_bool( 'auto_complete_downloadable', $profile );
$items = $order->get_items( 'line_item' );
if ( empty( $items ) ) { return false; }
foreach ( $items as $item ) {
$product = is_object( $item ) && method_exists( $item, 'get_product' ) ? $item->get_product() : null;
if ( ! $product ) { return false; }
$setting = $this->product_completion_setting( $product );
if ( 'exclude' === $setting ) { return false; }
$needs_shipping = method_exists( $product, 'needs_shipping' ) ? $product->needs_shipping() : ! $product->is_virtual();
if ( $needs_shipping ) { return false; }
if ( 'include' === $setting ) { continue; }
$is_virtual = method_exists( $product, 'is_virtual' ) && $product->is_virtual();
$is_downloadable = method_exists( $product, 'is_downloadable' ) && $product->is_downloadable();
if ( ! ( ( $allow_virtual && $is_virtual ) || ( $allow_downloadable && $is_downloadable ) ) ) { return false; }
}
return (bool) apply_filters( 'divi_powers_commerce_order_auto_complete_eligible', true, $order, $profile, $zero_total );
}
private function order_has_incompatible_fulfillment( $order ) {
if ( function_exists( 'wcs_order_contains_subscription' ) && wcs_order_contains_subscription( $order ) ) { return true; }
if ( function_exists( 'wcs_order_contains_renewal' ) && wcs_order_contains_renewal( $order ) ) { return true; }
foreach ( $order->get_items( 'line_item' ) as $item ) {
$product = is_object( $item ) && method_exists( $item, 'get_product' ) ? $item->get_product() : null;
/*
* Never force-complete a recurring parent or renewal order. Flexible
* Subscriptions must finish its own subscription transaction, schedule,
* and redirect before any fulfillment automation runs.
*/
if ( $product && $this->product_is_recurring( $product, $item ) ) {
return true;
}
$type = $product && method_exists( $product, 'get_type' ) ? strtolower( (string) $product->get_type() ) : '';
foreach ( array( 'subscription', 'booking', 'appointment', 'pre_order', 'pre-order', 'deposit', 'rental' ) as $blocked ) {
if ( $type && false !== strpos( $type, $blocked ) ) { return true; }
}
}
return (bool) apply_filters( 'divi_powers_commerce_order_has_incompatible_fulfillment', false, $order );
}
public function filter_sold_individually( $sold_individually, $product ) {
if ( ! $this->runtime_enabled() || ! is_object( $product ) ) { return $sold_individually; }
return ( $this->product_force_one( $product ) || $this->effective_bool( 'force_quantity_one', $this->active_profile() ) ) ? true : $sold_individually;
}
public function normalize_cart_quantities( $cart ) {
if ( ! $this->runtime_enabled() || ! is_object( $cart ) || ! method_exists( $cart, 'get_cart' ) ) { return; }
$profile = $this->active_profile();
foreach ( $cart->get_cart() as $key => $item ) {
$product = isset( $item['data'] ) ? $item['data'] : null;
if ( $product && ( $this->product_force_one( $product ) || $this->effective_bool( 'force_quantity_one', $profile ) ) && isset( $item['quantity'] ) && (int) $item['quantity'] !== 1 ) {
$cart->set_quantity( $key, 1, false );
}
}
}
public function filter_product_visibility( $visible, $product_id ) {
return $this->runtime_enabled() && $this->product_meta_bool( $product_id, self::PRODUCT_FUNNEL_ONLY_META ) ? false : $visible;
}
public function filter_repeat_purchase_purchasable( $purchasable, $product ) {
if ( ! $purchasable || ! $this->runtime_enabled() || ! is_user_logged_in() || ! is_object( $product ) || ! function_exists( 'wc_customer_bought_product' ) ) { return $purchasable; }
$product_id = $this->product_parent_aware_id( $product );
if ( ! $this->product_meta_bool( $product_id, self::PRODUCT_REPEAT_META ) ) { return $purchasable; }
$user = wp_get_current_user();
return wc_customer_bought_product( $user->user_email, $user->ID, $product_id ) ? false : $purchasable;
}
public function validate_repeat_purchases( $data, $errors ) {
if ( ! $this->runtime_enabled() || ! function_exists( 'WC' ) || ! WC() || ! WC()->cart || ! function_exists( 'wc_customer_bought_product' ) || ! is_object( $errors ) ) { return; }
$email = isset( $data['billing_email'] ) ? sanitize_email( $data['billing_email'] ) : '';
$user_id = get_current_user_id();
if ( ! $email && $user_id ) { $email = wp_get_current_user()->user_email; }
if ( ! $email ) { return; }
foreach ( WC()->cart->get_cart() as $item ) {
$product = isset( $item['data'] ) ? $item['data'] : null;
if ( ! $product ) { continue; }
$product_id = $this->product_parent_aware_id( $product );
if ( $this->product_meta_bool( $product_id, self::PRODUCT_REPEAT_META ) && wc_customer_bought_product( $email, $user_id, $product_id ) ) {
$errors->add( 'divi_powers_repeat_purchase', sprintf(
/* translators: %s: purchased product name. */
__( 'You have already purchased “%s”. Please sign in with the original account or contact support if you need another license.', '5d-powers-for-divi' ), $product->get_name() ) );
}
}
}
public function filter_add_to_cart_redirect( $url, $adding_to_cart = null ) {
if ( ! $this->runtime_enabled() ) { return $url; }
$is_buy_now = isset( $_REQUEST['dp_buy_now'] ) || isset( $_REQUEST['dp_direct_checkout'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
if ( ! $is_buy_now && ! $this->settings()['direct_checkout'] ) { return $url; }
$product_id = $this->product_id_from_add_request( $adding_to_cart );
$profile = $product_id ? apply_filters( 'divi_powers_woo_profile_for_product', null, $product_id ) : null;
if ( is_array( $profile ) && ! empty( $profile['checkout_route_url'] ) ) {
if ( ! $is_buy_now ) { return $profile['checkout_route_url']; }
$args = array( 'dp_buy_now' => $product_id, 'quantity' => $this->request_buy_now_quantity( false ) );
foreach ( array( 'dp_coupon', 'utm_source', 'utm_campaign' ) as $key ) {
if ( isset( $_REQUEST[ $key ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$request_value = sanitize_text_field( wp_unslash( $_REQUEST[ $key ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
if ( '' !== $request_value ) { $args[ $key ] = $request_value; }
}
}
return add_query_arg( $args, $profile['checkout_route_url'] );
}
return function_exists( 'wc_get_checkout_url' ) ? wc_get_checkout_url() : $url;
}
public function maybe_isolate_added_item( $cart_item_key, $product_id, $quantity, $variation_id, $variation, $cart_item_data ) {
if ( ! $this->runtime_enabled() || ! function_exists( 'WC' ) || ! WC() || ! WC()->cart ) { return; }
$is_buy_now = isset( $_REQUEST['dp_buy_now'] ) || isset( $_REQUEST['dp_direct_checkout'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$profile = apply_filters( 'divi_powers_woo_profile_for_product', null, $variation_id ? $variation_id : $product_id );
$is_profile = is_array( $profile );
$definition = $is_profile && isset( $profile['definition'] ) && is_array( $profile['definition'] ) ? $profile['definition'] : array();
$replace_profile_cart = $is_profile && 'replace' === sanitize_key( isset( $definition['cart_behavior'] ) ? $definition['cart_behavior'] : '' );
$isolate_profile_cart = $is_profile && $this->effective_bool( 'cart_isolation', $profile );
$isolate_buy_now = $is_buy_now && $this->effective_bool( 'cart_isolation', $is_profile ? $profile : null );
if ( ! $replace_profile_cart && ! $isolate_profile_cart && ! $isolate_buy_now ) { return; }
foreach ( array_keys( WC()->cart->get_cart() ) as $key ) {
if ( (string) $key !== (string) $cart_item_key ) { WC()->cart->remove_cart_item( $key ); }
}
}
public function filter_registration_enabled( $enabled ) {
$behavior = $this->effective_account_behavior();
if ( 'guest' === $behavior ) { return false; }
if ( in_array( $behavior, array( 'optional', 'required', 'auto' ), true ) ) { return true; }
return $enabled;
}
public function filter_registration_required( $required ) {
$behavior = $this->effective_account_behavior();
if ( 'required' === $behavior ) { return true; }
if ( in_array( $behavior, array( 'guest', 'optional', 'auto' ), true ) ) { return false; }
return $required;
}
public function filter_checkout_posted_data( $data ) {
if ( 'auto' === $this->effective_account_behavior() && ! is_user_logged_in() ) { $data['createaccount'] = 1; }
return $data;
}
public function filter_order_button_text( $text ) {
if ( ! $this->runtime_enabled() ) { return $text; }
$profile = $this->active_profile();
$profile_text = is_array( $profile ) && ! empty( $profile['definition']['commerce_order_button_text'] )
? $profile['definition']['commerce_order_button_text']
: '';
if ( $profile_text ) {
return $profile_text;
}
$settings = $this->settings();
if ( $this->cart_is_safe_free_checkout() ) {
$free_text = $this->effective_free_checkout_button_text( $profile );
if ( $free_text ) {
return $free_text;
}
}
return $settings['order_button_text'] ? $settings['order_button_text'] : $text;
}
/**
* WooCommerce normally skips payment for a zero total. This late filter
* restores that behavior when another extension has forced payment back on.
*/
public function filter_cart_needs_payment( $needs_payment, $cart ) {
if ( ! $this->runtime_enabled() || ! $this->effective_bool( 'free_checkout_no_payment', $this->active_profile() ) ) {
return $needs_payment;
}
return $this->cart_is_safe_free_checkout( $cart ) ? false : $needs_payment;
}
/**
* Apply the same protection to order-pay and retry screens.
*/
public function filter_order_needs_payment( $needs_payment, $order, $valid_order_statuses = array() ) {
unset( $valid_order_statuses );
if ( ! $this->runtime_enabled() || ! $this->effective_bool( 'free_checkout_no_payment', $this->profile_for_order( $order ) ) ) {
return $needs_payment;
}
return $this->order_is_safe_free_checkout( $order ) ? false : $needs_payment;
}
/**
* Gateway UI fallback for extensions that expose payment choices even after
* WooCommerce reports that the cart does not need payment.
*/
public function filter_free_checkout_gateways( $gateways ) {
if (
! $this->runtime_enabled()
|| ! is_array( $gateways )
|| ! $this->effective_bool( 'free_checkout_no_payment', $this->active_profile() )
) {
return $gateways;
}
return $this->cart_is_safe_free_checkout() ? array() : $gateways;
}
/**
* Optional Classic Checkout cleanup for free, shipping-free digital orders.
*/
public function filter_free_checkout_fields( $fields ) {
$profile = $this->active_profile();
if (
! $this->runtime_enabled()
|| ! $this->effective_bool( 'free_checkout_trim_billing', $profile )
|| ! is_array( $fields )
|| ! $this->cart_is_safe_free_checkout()
|| ! $this->cart_is_shipping_free()
) {
return $fields;
}
$remove = array(
'billing_company',
'billing_country',
'billing_address_1',
'billing_address_2',
'billing_city',
'billing_state',
'billing_postcode',
'billing_phone',
);
foreach ( $remove as $key ) {
unset( $fields['billing'][ $key ] );
}
return $fields;
}
private function cart_is_safe_free_checkout( $cart = null ) {
if ( ! $this->runtime_enabled() ) {
return false;
}
if ( ! is_object( $cart ) && function_exists( 'WC' ) && WC() ) {
$cart = WC()->cart;
}
if ( ! is_object( $cart ) ) {
return false;
}
$total = method_exists( $cart, 'get_total' )
? (float) $cart->get_total( 'edit' )
: (float) ( $cart->total ?? 0 );
if ( $total > 0.00001 ) {
return false;
}
$profile = $this->active_profile();
$has_recurring = $this->cart_has_recurring_item( $cart );
if ( $has_recurring ) {
$mode = $this->effective_free_checkout_subscription_mode( $profile );
if ( 'require' === $mode ) {
return false;
}
if ( 'skip' !== $mode ) {
/*
* Flexible Subscriptions can display a recurring total that is
* different from the product's catalog price after recurring
* coupons. Trust the calculated recurring cart/coupon result
* before falling back to the product's original renewal price.
*/
if ( ! $this->recurring_cart_total_is_zero( $cart ) && $this->cart_has_future_paid_recurring_item( $cart ) ) {
return false;
}
}
}
return (bool) apply_filters( 'divi_powers_safe_free_checkout_cart', true, $cart );
}
private function order_is_safe_free_checkout( $order ) {
if ( ! is_object( $order ) || ! method_exists( $order, 'get_total' ) ) {
return false;
}
if ( (float) $order->get_total() > 0.00001 ) {
return false;
}
$profile = $this->profile_for_order( $order );
$mode = $this->effective_free_checkout_subscription_mode( $profile );
if ( 'require' === $mode && $this->order_has_recurring_item( $order ) ) {
return false;
}
if (
'auto' === $mode
&& $this->order_has_recurring_item( $order )
&& $this->order_has_future_paid_recurring_item( $order )
) {
return false;
}
return (bool) apply_filters( 'divi_powers_safe_free_checkout_order', true, $order );
}
/**
* Flexible Subscriptions can independently request a card for a free trial.
* Keep that request only when the configured subscription behavior says the
* cart has a future paid renewal.
*/
public function filter_flexible_subscription_payment_requirement( $require_payment ) {
if (
! $this->runtime_enabled()
|| ! $this->effective_bool( 'free_checkout_no_payment', $this->active_profile() )
) {
return $require_payment;
}
if ( $this->cart_is_safe_free_checkout() ) {
return false;
}
return 'require' === $this->effective_free_checkout_subscription_mode( $this->active_profile() )
? true
: $require_payment;
}
private function cart_is_shipping_free() {
if ( ! function_exists( 'WC' ) || ! WC() || ! WC()->cart ) {
return false;
}
if ( method_exists( WC()->cart, 'needs_shipping' ) && WC()->cart->needs_shipping() ) {
return false;
}
foreach ( WC()->cart->get_cart() as $item ) {
$product = isset( $item['data'] ) && is_object( $item['data'] ) ? $item['data'] : null;
if ( $product && method_exists( $product, 'is_virtual' ) && ! $product->is_virtual() ) {
return false;
}
}
return true;
}
private function cart_has_recurring_item( $cart ) {
if ( ! is_object( $cart ) || ! method_exists( $cart, 'get_cart' ) ) {
return false;
}
foreach ( $cart->get_cart() as $item ) {
$product = isset( $item['data'] ) && is_object( $item['data'] )
? $item['data']
: ( function_exists( 'wc_get_product' ) ? wc_get_product( absint( $item['variation_id'] ?? $item['product_id'] ?? 0 ) ) : null );
if ( $product && $this->product_is_recurring( $product, $item ) ) {
return true;
}
}
return false;
}
private function order_has_recurring_item( $order ) {
if ( ! is_object( $order ) || ! method_exists( $order, 'get_items' ) ) {
return false;
}
foreach ( $order->get_items() as $item ) {
$product = is_object( $item ) && method_exists( $item, 'get_product' ) ? $item->get_product() : null;
if ( $product && $this->product_is_recurring( $product, $item ) ) {
return true;
}
}
return false;
}
private function cart_has_future_paid_recurring_item( $cart ) {
if ( ! is_object( $cart ) || ! method_exists( $cart, 'get_cart' ) ) {
return false;
}
foreach ( $cart->get_cart() as $item ) {
$product = isset( $item['data'] ) && is_object( $item['data'] )
? $item['data']
: ( function_exists( 'wc_get_product' ) ? wc_get_product( absint( $item['variation_id'] ?? $item['product_id'] ?? 0 ) ) : null );
if ( $product && $this->product_has_future_paid_recurrence( $product, $item ) ) {
return true;
}
}
return false;
}
private function order_has_future_paid_recurring_item( $order ) {
if ( ! is_object( $order ) || ! method_exists( $order, 'get_items' ) ) {
return false;
}
foreach ( $order->get_items() as $item ) {
$product = is_object( $item ) && method_exists( $item, 'get_product' ) ? $item->get_product() : null;
if ( $product && $this->product_has_future_paid_recurrence( $product, $item ) ) {
return true;
}
}
return false;
}
/**
* Read a calculated recurring total when a subscription plugin exposes one.
* Flexible Subscriptions maintains WooCommerce-Subscriptions-compatible
* structures in several checkout paths, while recurring coupons provide a
* dependable fallback for a fully discounted renewal.
*/
private function recurring_cart_total_is_zero( $cart ) {
$filtered = apply_filters( 'divi_powers_recurring_cart_total', null, $cart );
if ( null !== $filtered && is_numeric( $filtered ) ) {
return (float) $filtered <= 0.00001;
}
$recurring_carts = array();
if ( method_exists( $cart, 'get_recurring_carts' ) ) {
$recurring_carts = $cart->get_recurring_carts();
} elseif ( isset( $cart->recurring_carts ) ) {
$recurring_carts = $cart->recurring_carts;
}
if ( is_array( $recurring_carts ) && $recurring_carts ) {
$found = false;
foreach ( $recurring_carts as $recurring_cart ) {
if ( ! is_object( $recurring_cart ) ) {
continue;
}
$found = true;
$total = method_exists( $recurring_cart, 'get_total' )
? (float) $recurring_cart->get_total( 'edit' )
: (float) ( $recurring_cart->total ?? 0 );
if ( $total > 0.00001 ) {
return false;
}
}
if ( $found ) {
return true;
}
}
if ( $this->recurring_coupon_zeroes_cart( $cart ) ) {
return true;
}
/*
* Some Flexible Subscriptions versions store calculated recurring totals
* in WooCommerce session data. Inspect only keys explicitly describing
* a recurring/renewal total and ignore unrelated numeric values.
*/
if ( function_exists( 'WC' ) && WC() && WC()->session && method_exists( WC()->session, 'get_session_data' ) ) {
$values = array();
$this->collect_recurring_total_values( WC()->session->get_session_data(), $values );
if ( $values ) {
foreach ( $values as $value ) {
if ( (float) $value > 0.00001 ) {
return false;
}
}
return true;
}
}
return false;
}
private function recurring_coupon_zeroes_cart( $cart ) {
if ( ! method_exists( $cart, 'get_applied_coupons' ) || ! class_exists( 'WC_Coupon' ) ) {
return false;
}
$recurring_base = 0.0;
foreach ( $cart->get_cart() as $item ) {
$product = isset( $item['data'] ) && is_object( $item['data'] ) ? $item['data'] : null;
if ( ! $product || ! $this->product_is_recurring( $product, $item ) ) {
continue;
}
$quantity = max( 1, absint( $item['quantity'] ?? 1 ) );
$price = method_exists( $product, 'get_regular_price' )
? (float) $product->get_regular_price( 'edit' )
: (float) $product->get_price( 'edit' );
$recurring_base += max( 0, $price ) * $quantity;
}
$fixed_recurring_discount = 0.0;
foreach ( $cart->get_applied_coupons() as $code ) {
$coupon = new WC_Coupon( $code );
$type = strtolower( (string) $coupon->get_discount_type() );
$amount = (float) $coupon->get_amount();
$is_recurring = false !== strpos( $type, 'recurr' )
|| false !== strpos( $type, 'renew' );
if ( ! $is_recurring ) {
foreach ( array( '_fsub_recurring', 'fsub_recurring', '_subscription_recurring', '_wcs_apply_to_renewals' ) as $key ) {
$value = strtolower( (string) $coupon->get_meta( $key, true ) );
if ( in_array( $value, array( 'yes', '1', 'true', 'on', 'recurring' ), true ) ) {
$is_recurring = true;
break;
}
}
}
if ( ! $is_recurring ) {
continue;
}
if ( false !== strpos( $type, 'percent' ) && $amount >= 99.999 ) {
return true;
}
if ( false !== strpos( $type, 'fixed' ) ) {
$fixed_recurring_discount += $amount;
}
}
return $recurring_base > 0 && $fixed_recurring_discount + 0.00001 >= $recurring_base;
}
private function collect_recurring_total_values( $value, &$values, $key = '' ) {
if ( is_array( $value ) ) {
foreach ( $value as $child_key => $child ) {
$this->collect_recurring_total_values( $child, $values, (string) $child_key );
}
return;
}
if (
is_numeric( $value )
&& preg_match( '/(?:recurr|renew|subscription).*(?:total|amount)|(?:total|amount).*(?:recurr|renew|subscription)/i', $key )
) {
$values[] = (float) $value;
}
}
private function product_is_recurring( $product, $context = null ) {
if ( ! is_object( $product ) || ! method_exists( $product, 'get_id' ) ) {
return false;
}
$product_id = absint( $product->get_id() );
$parent_id = method_exists( $product, 'get_parent_id' ) ? absint( $product->get_parent_id() ) : 0;
$lookup_id = $parent_id ? $parent_id : $product_id;
$is_recurring = false;
if ( class_exists( 'WC_Subscriptions_Product' ) && is_callable( array( 'WC_Subscriptions_Product', 'is_subscription' ) ) ) {
$is_recurring = (bool) WC_Subscriptions_Product::is_subscription( $product );
}
if ( ! $is_recurring && function_exists( 'wcs_is_subscription_product' ) ) {
$is_recurring = (bool) wcs_is_subscription_product( $product_id );
}
if ( ! $is_recurring && function_exists( 'wps_sfw_is_product_subscription' ) ) {
$is_recurring = (bool) wps_sfw_is_product_subscription( $lookup_id );
}
if ( ! $is_recurring && method_exists( $product, 'get_type' ) ) {
$type = strtolower( (string) $product->get_type() );
$is_recurring = false !== strpos( $type, 'subscription' );
}
if ( ! $is_recurring && false !== strpos( get_class( $product ), 'FlexibleSubscriptions' ) ) {
$is_recurring = true;
}
if ( ! $is_recurring ) {
foreach (
array(
'_subscription_period',
'_subscription_period_interval',
'_subscription_price',
'_wps_sfw_product',
'wps_sfw_product',
'_wps_sfw_subscription',
'wps_sfw_subscription',
) as $key
) {
$value = get_post_meta( $lookup_id, $key, true );
if ( '' !== (string) $value && ! in_array( strtolower( (string) $value ), array( 'no', '0', 'false', 'off' ), true ) ) {
$is_recurring = true;
break;
}
}
}
return (bool) apply_filters(
'divi_powers_product_is_recurring',
$is_recurring,
$product,
$context
);
}
private function product_has_future_paid_recurrence( $product, $context = null ) {
if ( ! $this->product_is_recurring( $product, $context ) ) {
return false;
}
$product_id = absint( $product->get_id() );
$parent_id = method_exists( $product, 'get_parent_id' ) ? absint( $product->get_parent_id() ) : 0;
$lookup_id = $parent_id ? $parent_id : $product_id;
$amounts = array();
foreach ( array( 'get_price', 'get_regular_price' ) as $method ) {
if ( method_exists( $product, $method ) ) {
$amounts[] = (float) $product->{$method}( 'edit' );
}
}
foreach (
array(
'_price',
'_regular_price',
'_subscription_price',
'_wps_sfw_subscription_price',
'wps_sfw_subscription_price',
) as $key
) {
$amounts[] = (float) get_post_meta( $lookup_id, $key, true );
}
$future_amount = max( array_merge( array( 0.0 ), $amounts ) );
return (float) apply_filters(
'divi_powers_recurring_product_future_amount',
$future_amount,
$product,
$context
) > 0.00001;
}
private function effective_free_checkout_subscription_mode( $profile = null ) {
if ( is_array( $profile ) && isset( $profile['definition'] ) && is_array( $profile['definition'] ) ) {
$value = sanitize_key( (string) ( $profile['definition']['commerce_free_checkout_subscription_mode'] ?? 'inherit' ) );
if ( in_array( $value, array( 'auto', 'skip', 'require' ), true ) ) {
return $value;
}
}
$value = sanitize_key( (string) ( $this->settings()['free_checkout_subscription_mode'] ?? 'auto' ) );
return in_array( $value, array( 'auto', 'skip', 'require' ), true ) ? $value : 'auto';
}
private function effective_free_checkout_button_text( $profile = null ) {
if ( is_array( $profile ) && isset( $profile['definition'] ) && is_array( $profile['definition'] ) ) {
$value = substr( sanitize_text_field( $profile['definition']['commerce_free_checkout_button_text'] ?? '' ), 0, 80 );
if ( $value ) {
return $value;
}
}
return substr( sanitize_text_field( $this->settings()['free_checkout_button_text'] ?? 'Complete order' ), 0, 80 );
}
public function capture_campaign_coupon() {
if ( ! $this->runtime_enabled() || empty( $_GET['dp_coupon'] ) || ! function_exists( 'WC' ) || ! WC() || ! WC()->session ) { return; } // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$profile = $this->active_profile();
if ( ! $profile && function_exists( 'get_query_var' ) ) {
$route = get_query_var( 'dp_checkout_journey' );
if ( $route ) { $profile = apply_filters( 'divi_powers_woo_profile_by_slug', null, $route ); }
}
if ( ! $this->effective_bool( 'coupon_links', is_array( $profile ) ? $profile : null ) ) { return; }
$posted_code = sanitize_text_field( wp_unslash( $_GET['dp_coupon'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$code = function_exists( 'wc_format_coupon_code' ) ? wc_format_coupon_code( $posted_code ) : $posted_code;
if ( $code ) { WC()->session->set( self::PENDING_COUPON_SESSION, $code ); }
}
public function apply_pending_coupon() {
if ( ! $this->runtime_enabled() || ! function_exists( 'WC' ) || ! WC() || ! WC()->session || ! WC()->cart ) { return; }
$code = WC()->session->get( self::PENDING_COUPON_SESSION );
if ( ! $code ) { return; }
if ( ! $this->effective_bool( 'coupon_links', $this->active_profile() ) ) { WC()->session->__unset( self::PENDING_COUPON_SESSION ); return; }
if ( WC()->cart->is_empty() ) { return; }
if ( ! WC()->cart->has_discount( $code ) ) { WC()->cart->apply_coupon( $code ); }
WC()->session->__unset( self::PENDING_COUPON_SESSION );
}
public function filter_coupons_enabled( $enabled ) {
if ( ! $enabled || ! $this->runtime_enabled() || ! $this->effective_bool( 'hide_coupon_after_apply', $this->active_profile() ) || ! function_exists( 'WC' ) || ! WC() || ! WC()->cart ) { return $enabled; }
return WC()->cart->get_applied_coupons() ? false : $enabled;
}
private function effective_account_behavior() {
if ( ! $this->runtime_enabled() ) { return 'default'; }
$profile = $this->active_profile();
if ( is_array( $profile ) ) {
$value = sanitize_key( (string) ( $profile['definition']['commerce_account_behavior'] ?? 'inherit' ) );
if ( 'inherit' !== $value && in_array( $value, array( 'default', 'guest', 'optional', 'required', 'auto' ), true ) ) { return $value; }
}
return $this->settings()['account_behavior'];
}
private function effective_bool( $key, $profile = null ) {
$settings = $this->settings();
if ( is_array( $profile ) && isset( $profile['definition'] ) && is_array( $profile['definition'] ) ) {
$override_key = 'commerce_' . $key;
$value = isset( $profile['definition'][ $override_key ] ) ? sanitize_key( (string) $profile['definition'][ $override_key ] ) : 'inherit';
if ( 'enabled' === $value ) { return true; }
if ( 'disabled' === $value ) { return false; }
}
return ! empty( $settings[ $key ] );
}
private function active_profile() {
$profile = apply_filters( 'divi_powers_woo_active_journey_profile', null );
return is_array( $profile ) ? $profile : null;
}
private function profile_for_order( $order ) {
if ( ! is_object( $order ) || ! method_exists( $order, 'get_meta' ) ) { return null; }
$id = absint( $order->get_meta( '_divi_powers_woo_profile_id', true ) );
$profile = $id ? apply_filters( 'divi_powers_woo_profile_by_id', null, $id ) : null;
return is_array( $profile ) ? $profile : null;
}
private function product_completion_setting( $product ) {
$id = $this->product_parent_aware_id( $product );
$value = sanitize_key( (string) get_post_meta( $id, self::PRODUCT_COMPLETE_META, true ) );
return in_array( $value, array( 'include', 'exclude' ), true ) ? $value : 'inherit';
}
private function product_force_one( $product ) {
return $this->product_meta_bool( $this->product_parent_aware_id( $product ), self::PRODUCT_FORCE_ONE_META );
}
private function product_parent_aware_id( $product ) {
if ( ! is_object( $product ) || ! method_exists( $product, 'get_id' ) ) { return 0; }
$parent = method_exists( $product, 'get_parent_id' ) ? absint( $product->get_parent_id() ) : 0;
return $parent ? $parent : absint( $product->get_id() );
}
private function product_meta_bool( $product_id, $key ) {
$product_id = absint( $product_id );
if ( ! $product_id ) { return false; }
if ( get_post_meta( $product_id, $key, true ) ) { return true; }
$parent = function_exists( 'wp_get_post_parent_id' ) ? absint( wp_get_post_parent_id( $product_id ) ) : 0;
return $parent ? (bool) get_post_meta( $parent, $key, true ) : false;
}
private function request_buy_now_product_id( $include_session = true ) {
$product_id = 0;
if ( isset( $_REQUEST['dp_buy_now'] ) && is_numeric( $_REQUEST['dp_buy_now'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$product_id = absint( $_REQUEST['dp_buy_now'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
if ( 1 === $product_id && isset( $_REQUEST['add-to-cart'] ) ) { $product_id = absint( $_REQUEST['add-to-cart'] ); } // phpcs:ignore WordPress.Security.NonceVerification.Recommended
}
if ( ! $product_id && $include_session && function_exists( 'WC' ) && WC() && WC()->session ) { $product_id = absint( WC()->session->get( self::BUY_NOW_PRODUCT_SESSION ) ); }
return $product_id;
}
private function request_buy_now_quantity( $include_session = true ) {
$quantity = isset( $_REQUEST['quantity'] ) ? absint( $_REQUEST['quantity'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
if ( ! $quantity && $include_session && function_exists( 'WC' ) && WC() && WC()->session ) { $quantity = absint( WC()->session->get( self::BUY_NOW_QUANTITY_SESSION ) ); }
return max( 1, min( 99, $quantity ? $quantity : 1 ) );
}
private function product_id_from_add_request( $adding_to_cart ) {
if ( is_object( $adding_to_cart ) && method_exists( $adding_to_cart, 'get_id' ) ) { return absint( $adding_to_cart->get_id() ); }
if ( is_numeric( $adding_to_cart ) ) { return absint( $adding_to_cart ); }
if ( isset( $_REQUEST['add-to-cart'] ) ) { return absint( $_REQUEST['add-to-cart'] ); } // phpcs:ignore WordPress.Security.NonceVerification.Recommended
return $this->request_buy_now_product_id();
}
private function get_buy_now_products() {
if ( ! function_exists( 'wc_get_product' ) ) { return array(); }
$ids = get_posts( array( 'post_type' => array( 'product', 'product_variation' ), 'post_status' => 'publish', 'posts_per_page' => 250, 'fields' => 'ids', 'orderby' => 'title', 'order' => 'ASC' ) );
$items = array();
foreach ( $ids as $id ) {
$product = wc_get_product( $id );
if ( ! $product || ! $product->is_purchasable() || ( method_exists( $product, 'is_type' ) && $product->is_type( 'variable' ) ) ) { continue; }
$name = $product->get_name();
$price = method_exists( $product, 'get_price_html' ) ? wp_strip_all_tags( $product->get_price_html() ) : '';
$items[] = array( 'id' => absint( $id ), 'label' => $name . ( $price ? ' — ' . $price : '' ) . ' (#' . absint( $id ) . ')' );
}
return $items;
}
private function runtime_enabled() {
return $this->plugin->is_power_enabled( 'commerce_utilities' ) && $this->woo_available();
}
private function woo_available() {
return class_exists( 'WooCommerce' ) || function_exists( 'WC' );
}
}