options = $options; add_action( 'wp_print_styles', array( $this, 'load_frontend_assets' ) ); $this->price_display = new WDP_Price_Display(); if ( $this->price_display->is_enabled() ) { add_action( 'wp_loaded', array( $this, 'wp_loaded_process_cart' ), PHP_INT_MAX ); } if ( ( $options['update_prices_while_doing_rest_api'] && $this->price_display->is_request_to_rest_api() ) || ( $options['update_prices_while_doing_cron'] && wp_doing_cron() ) ) { $this->price_display->init_while_doing_cron_or_rest_api(); } add_action( 'woocommerce_checkout_order_processed', array( $this, 'checkout_order_processed' ), 10, 3 ); if ( apply_filters( 'wdp_checkout_update_order_review_process_enabled', true ) ) { add_action( 'woocommerce_checkout_update_order_review', array( $this, 'woocommerce_checkout_update_order_review' ), 100 ); } if ( $options['support_shortcode_products_on_sale'] ) { WDP_Shortcode_Products_On_Sale::register(); } if( $options['support_shortcode_products_bogo'] ) { WDP_Shortcode_Products_Bogo::register(); } // hooking nopriv ajax methods add_action( "wp_ajax_nopriv_get_price_product_with_bulk_table", array( $this, "ajax_get_price_product_with_bulk_table" ) ); add_action( "wp_ajax_get_price_product_with_bulk_table", array( $this, "ajax_get_price_product_with_bulk_table" ) ); if ( $options['suppress_other_pricing_plugins'] AND !is_admin() ) { add_action( "wp_loaded", array( $this, 'remove_hooks_set_by_other_plugins' ) ); } add_filter( 'woocommerce_cart_id', array( $this, 'woocommerce_cart_id' ), 10, 5 ); add_filter( 'woocommerce_add_to_cart_sold_individually_found_in_cart', array($this, 'woocommerce_add_to_cart_sold_individually_found_in_cart'), 10 ,5 ); add_filter( 'woocommerce_order_again_cart_item_data', function ( $cart_item, $item, $order ) { $load_as_immutable = apply_filters( 'wdp_order_again_cart_item_load_with_order_deals', false, $cart_item, $item, $order ); if ( $load_as_immutable ) { $rules = $item->get_meta( '_wdp_rules' ); if ( ! empty( $rules ) ) { $cart_item['wdp_rules'] = $rules; $cart_item['wdp_immutable'] = true; } } return $cart_item; }, 10, 3 ); add_action( 'woocommerce_checkout_create_order_line_item_object', array( $this, 'save_initial_price_to_order_item' ), 10, 4 ); if ( $options['hide_coupon_word_in_totals'] ) { add_filter( 'woocommerce_cart_totals_coupon_label', function ( $html, $coupon ) { /** * @var WC_Coupon $coupon */ if ( $coupon->get_description() && $coupon->get_virtual() ) { $html = $coupon->get_code(); } return $html; }, 5, 2 ); } /** Additional css class for free item line */ add_filter( 'woocommerce_cart_item_class', function ( $str_classes, $cart_item, $cart_item_key ) { $classes = explode( ' ', $str_classes ); if ( ! empty( $cart_item['wdp_gifted'] ) ) { $classes[] = 'wdp_free_product'; } if ( ! empty( $cart_item['wdp_rules'] ) && (float) $cart_item['data']->get_price() == 0 ) { $classes[] = 'wdp_zero_cost_product'; } return implode( ' ', $classes ); }, 10, 3 ); // kill on calculate totals action because it conflicts with Phone Orders add_action( "wpo_before_update_cart", function () { remove_action( 'woocommerce_after_calculate_totals', array( $this, 'woocommerce_after_calculate_totals' ), PHP_INT_MAX ); }, 10, 0 ); /** PHONE ORDER HOOKS START */ add_action( 'wdp_force_process_wc_cart', function ( $wc_cart ) { WDP_Functions::process_cart_manually(); } ); add_filter( 'wpo_product_before_get_item', function ( $product, $item_data ) { if ( ! isset( $item_data['item_cost'] ) || ! is_numeric( $item_data['item_cost'] ) ) { $qty = isset( $item_data['quantity'] ) ? (float) $item_data['quantity'] : floatval( 1 ); $wdp_product = $this->price_display->process_product( $product, $qty ); if ( $wdp_product ) { $product->set_price( $wdp_product->get_new_price() ); } } return $product; }, 10, 2 ); add_action( 'wdp_after_switch_customer_while_calc', function () { $this->price_display->apply_cart(); }, 10 ); if ( ! $options['allow_to_edit_prices_in_po'] ) { add_filter( 'wpo_set_original_price_after_calculation', function ( $price, $cart_item ) { return isset( $cart_item["wdp_original_price"] ) ? $cart_item["wdp_original_price"] : false; }, 10, 2 ); add_filter( 'wpo_cart_item_is_price_readonly', '__return_true', 10, 1 ); /** * Restore initial price if pricing plugin made changes */ add_filter( 'wpo_prepare_item', function ( $item, $product ) { /** * @var $product WC_Product */ if ( $item['item_cost'] != $product->get_price() ) { $item['item_cost'] = $product->get_price(); } return $item; }, 10, 2 ); } else { add_filter( 'wpo_prepare_item', function ( $item, $product ) { /** * @var $product WC_Product */ if ( empty( $item['cost_updated_manually'] ) && ( $item['item_cost'] != $product->get_price() ) ) { $item['item_cost'] = $product->get_price(); } return $item; }, 10, 2 ); add_filter( 'wdp_prepare_cart_item', function ( $cart_item, $wc_cart_item ) { /** * @var $product WC_Product */ if ( ! empty( $wc_cart_item['cost_updated_manually'] ) ) { $cart_item->make_immutable(); } return $cart_item; }, 10, 2 ); add_filter( "wdp_get_product", function ( $product, $wc_cart_item ) { /** * @var $product WC_Product * @var $wc_cart_item array */ if ( ! empty( $wc_cart_item['wpo_item_cost'] ) ) { $product->set_price( $wc_cart_item['wpo_item_cost'] ); } return $product; }, 10, 2 ); add_filter( 'wpo_cart_item_is_price_readonly', '__return_false', 10, 1 ); } add_filter( 'wpo_must_switch_cart_user', '__return_true', 10, 1 ); add_filter( 'wpo_skip_add_to_cart_item', function ( $skip, $item ) { return ! empty( $item['wdp_gifted'] ) ? (boolean) $item['wdp_gifted'] : $skip; }, 10, 2 ); /** PHONE ORDER HOOKS FINISH */ } public function install_bulk_range_table( $customizer ) { $this->bulk_table = new WDP_Range_Discounts_Table( $this->price_display ); $this->discount_message = new WDP_Discount_Message(); $this->bulk_table->set_theme_options( $customizer ); } public function install_profiler( $profiler ) { if ( $this->price_display->is_enabled() ) { $this->profiler = $profiler; $this->profiler->use_price_display( $this->price_display ); $this->profiler->install(); } } /** * @param $item WC_Order_Item_Product * @param $cart_item_key string * @param $values array * @param $order WC_Order * * @return WC_Order_Item_Product */ public function save_initial_price_to_order_item( $item, $cart_item_key, $values, $order ) { if ( ! empty( $values['wdp_rules'] ) ) { $item->add_meta_data( '_wdp_rules', $values['wdp_rules'] ); } return $item; } public static function is_catalog_view() { return ! is_product() || ! empty( $GLOBALS['woocommerce_loop']['name'] ); } public function ajax_get_price_product_with_bulk_table() { $product_id = ! empty( $_REQUEST['product_id'] ) ? $_REQUEST['product_id'] : false; $qty = ! empty( $_REQUEST['qty'] ) ? (int) $_REQUEST['qty'] : false; $page_data = ! empty( $_REQUEST['page_data'] ) ? (array) $_REQUEST['page_data'] : array(); $is_product = isset( $page_data['is_product'] ) ? wc_string_to_bool( $page_data['is_product'] ) : null; if ( ! empty( $_REQUEST['custom_price'] ) ) { $custom_price = $_REQUEST['custom_price']; if ( preg_match( '/\d+\\' . wc_get_price_decimal_separator() . '\d+/', $custom_price, $matches ) !== false ) { $custom_price = floatval( reset( $matches ) ); } else { $custom_price = false; }; } else { $custom_price = false; } if ( ! $product_id || ! $qty ) { wp_send_json_error(); } try { $wdp_product = new WDP_Product( $product_id ); } catch ( Exception $e ) { wp_send_json_error(); return; } if ( $custom_price !== false ) { $wdp_product->set_price( $custom_price / $qty ); $wdp_product->get_wc_product()->set_price( $custom_price / $qty ); $wdp_product->use_custom_initial_price(); } $context_classname = WDP_Loader::get_context_class_name(); $context = $context_classname::make_context(); /** * @var $context WDP_Context */ $context->set_props( array( $context::IS_ADMIN => false, $context::IS_AJAX => false, $context::IS_PRODUCT_PAGE => $is_product, ) ); $formatter = WDP_Loader::create_formatter( $context ); /** * @var WDP_Price_Formatter $formatter */ if ( $formatter->are_modifications_needed( $wdp_product ) ) { $wdp_product = $this->price_display->process_product( $wdp_product, $qty ); } $this->price_display->remove_price_hooks(); $price_html = $formatter->format_price( $formatter->format_wdp_product_price( $wdp_product, 1 ), $wdp_product ); $subtotal_html = $formatter->format_price( $formatter->format_wdp_product_price( $wdp_product, $qty ), $wdp_product ); $this->price_display->restore_hooks(); $price_html = $formatter->maybe_add_subscription_tail( $price_html, $wdp_product ); $subtotal_html = $formatter->maybe_add_subscription_tail( $subtotal_html, $wdp_product ); wp_send_json_success( array( 'price_html' => $price_html, 'subtotal_html' => $subtotal_html, ) ); } /** * Change cart item display price * * @access public * * @param string $price_html * @param array $cart_item * @param string $cart_item_key * * @return string */ public function cart_item_price( $price_html, $cart_item, $cart_item_key ) { if ( isset( $cart_item['wdp_data']['initial_price'] ) ) { /** @var WC_Product $product */ $product = $cart_item['data']; $intial_price = $cart_item['wdp_data']['initial_price']; $processed_price = $product->get_price(); if ( $intial_price != $processed_price ) { $price_html = '' . wc_price( $intial_price ) . ''; $price_html .= '' . wc_price( $processed_price ) . ''; } } return $price_html; } public function wp_loaded_process_cart() { $this->process_cart(); add_action( 'woocommerce_after_calculate_totals', array( $this, 'woocommerce_after_calculate_totals' ), PHP_INT_MAX ); if ( ! empty( $_GET['wc-ajax'] ) ) { add_action( 'woocommerce_checkout_process', array( $this, 'process_cart' ), PHP_INT_MAX ); } } public function woocommerce_after_calculate_totals() { remove_action( 'woocommerce_after_calculate_totals', array( $this, 'woocommerce_after_calculate_totals' ), PHP_INT_MAX ); $this->price_display->remove_price_hooks(); $this->process_cart(); $this->price_display->restore_hooks(); add_action( 'woocommerce_after_calculate_totals', array( $this, 'woocommerce_after_calculate_totals' ), PHP_INT_MAX ); } public function woocommerce_checkout_update_order_review() { add_action( 'woocommerce_before_data_object_save', array( $this, 'process_cart' ), 100 ); $this->price_display->remove_price_hooks(); $this->process_cart(); $this->price_display->restore_hooks(); remove_action( 'woocommerce_before_data_object_save', array( $this, 'process_cart' ), 100 ); } public static function set_tax_exempt_before( $value ) { $value = wc_bool_to_string( boolval( $value ) ); WC()->session->set( "wdp_tax_exempt_before", $value ); } public static function get_tax_exempt_before() { $result = WC()->session->get( "wdp_tax_exempt_before", false ); return $result !== false ? wc_string_to_bool( $result ) : null; } public static function set_rule_tax_exempt( $value ) { $value = wc_bool_to_string( boolval( $value ) ); WC()->session->set( "wdp_rule_tax_exempt", $value ); } public static function get_rule_tax_exempt() { $result = WC()->session->get( "wdp_rule_tax_exempt", false ); return $result !== false ? wc_string_to_bool( $result ) : null; } public static function install_tax_exempt( $cart ) { $rule_tax_exempt = self::get_rule_tax_exempt(); if ( isset( $rule_tax_exempt ) ) { self::set_tax_exempt_before( WC()->customer->get_is_vat_exempt() ); WC()->customer->set_is_vat_exempt( $rule_tax_exempt ); } } public static function uninstall_tax_exempt( $cart ) { $tax_exempt_before = self::get_tax_exempt_before(); if ( isset( $tax_exempt_before ) ) { WC()->customer->set_is_vat_exempt( $tax_exempt_before ); } } public function process_cart() { remove_action( "woocommerce_before_calculate_totals", array( __CLASS__, "install_tax_exempt" ), 10 ); remove_action( "woocommerce_after_calculate_totals", array( __CLASS__, "uninstall_tax_exempt" ), 10 ); $selected_shipping_methods = WC()->session->get( 'chosen_shipping_methods' ); self::clearWcCartItems(); WC()->session->set( 'chosen_shipping_methods', $selected_shipping_methods ); $wc_customer = WC()->cart->get_customer(); $tax_exempt = $wc_customer->get_is_vat_exempt(); $calc = self::make_wdp_calc_from_wc(); $cart = self::make_wdp_cart_from_wc(); if ( ! empty( $this->profiler ) ) { $this->profiler->attach_listener( $calc ); } $this->price_display->attach_calc( $calc ); $newcart = $calc->main_process_cart( $cart ); if( $newcart ) { $newcart->apply_to_wc_cart(); } else if ( $cart->has_immutable_changed_items() ) { // renewal order items $cart->apply_to_wc_cart(); } else { //try delete gifted products ? $wc_cart_items = WC()->cart->get_cart(); $cart_helper = new WDP_WC_Cart_Translator(); foreach ( $wc_cart_items as $wc_cart_item_key => $wc_cart_item ) { $wc_cart_item = apply_filters( 'wdp_wc_cart_item_before_clear_from_rules_keys', $wc_cart_item, $wc_cart_item_key ); $changed = false; if ( isset( $wc_cart_item['wdp_gifted'] ) ) { $wdp_gifted = $wc_cart_item['wdp_gifted']; unset( $wc_cart_item['wdp_gifted'] ); $changed = true; if ( $wdp_gifted ) { WC()->cart->remove_cart_item( $wc_cart_item_key ); continue; } } if ( isset( $wc_cart_item['wdp_original_price'] ) ) { unset( $wc_cart_item['wdp_original_price'] ); $changed = true; } if ( isset( $wc_cart_item['wdp_history'] ) ) { unset( $wc_cart_item['wdp_history'] ); $changed = true; } if ( isset( $wc_cart_item['wdp_rules'] ) ) { unset( $wc_cart_item['wdp_rules'] ); $changed = true; } if ( isset( $wc_cart_item[ WDP_Cart::INITIAL_DATA_KEY ] ) ) { unset( $wc_cart_item[ WDP_Cart::INITIAL_DATA_KEY ] ); $changed = true; } if ( isset( $wc_cart_item['rules'] ) ) { unset( $wc_cart_item['rules'] ); $changed = true; } if ( isset( $wc_cart_item['wdp_rules_for_singular'] ) ) { unset( $wc_cart_item['wdp_rules_for_singular'] ); $changed = true; } $product_id = $wc_cart_item['product_id']; $qty = $wc_cart_item['quantity']; $variation_id = $wc_cart_item['variation_id']; $variation = $wc_cart_item['variation']; $store_keys = apply_filters( 'wdp_save_cart_item_keys', array(), $cart_helper->get_external_keys( $wc_cart_item ) ); $cart_item_data = array(); foreach ( $store_keys as $key ) { if ( isset( $wc_cart_item[ $key ] ) ) { $cart_item_data[ $key ] = $wc_cart_item[ $key ]; } } if ( $changed ) { WC()->cart->remove_cart_item( $wc_cart_item_key ); $exclude_hooks = apply_filters('wdp_exclude_hooks_when_add_to_cart_after_disable_pricing', array(), $wc_cart_item); $key = self::process_without_hooks( function () use ( $product_id, $qty, $variation_id, $variation, $cart_item_data ) { return WC()->cart->add_to_cart( $product_id, $qty, $variation_id, $variation, $cart_item_data ); }, $exclude_hooks ); do_action( "wdp_restore_cart_item_hash", $key, $wc_cart_item, $wc_cart_item_key ); } } $is_free_shipping_key = '_wdp_free_shipping'; // clear shipping in session for triggering full calculate_shipping to replace '_wdp_free_shipping' when needed foreach ( WC()->session->get_session_data() as $key => $value ) { if ( preg_match( '/(shipping_for_package_).*/', $key, $matches ) === 1 ) { if ( ! isset( $matches[0] ) ) { continue; } $stored_rates = WC()->session->get( $matches[0] ); if ( ! isset( $stored_rates['rates'] ) ) { continue; } if ( is_array( $stored_rates['rates'] ) ) { foreach ( $stored_rates['rates'] as $rate ) { if ( isset( $rate->get_meta_data()[$is_free_shipping_key] ) ) { unset( WC()->session->$key ); break; } } } } } }// if no rules $this->price_display->apply_cart(); add_action( "woocommerce_before_calculate_totals", array( __CLASS__, "install_tax_exempt" ), 10, 1 ); add_action( "woocommerce_after_calculate_totals", array( __CLASS__, "uninstall_tax_exempt" ), 10, 1 ); self::set_rule_tax_exempt( $wc_customer->get_is_vat_exempt() ); $wc_customer->set_is_vat_exempt( $tax_exempt ); /** * fixed: Coupon could not be added! * We processing the cart AFTER 'set_session' call using hook. * So, we remove added coupons during wc-ajax. * Let do it manually. * * @see \WC_Cart_Session::init() */ ( new \WC_Cart_Session( WC()->cart ) )->set_session(); } public static function process_cart_manually() { remove_action( "woocommerce_before_calculate_totals", array( __CLASS__, "install_tax_exempt" ), 10 ); remove_action( "woocommerce_after_calculate_totals", array( __CLASS__, "uninstall_tax_exempt" ), 10 ); $selected_shipping_methods = WC()->session->get( 'chosen_shipping_methods' ); self::clearWcCartItems(); WC()->session->set( 'chosen_shipping_methods', $selected_shipping_methods ); $wc_customer = WC()->cart->get_customer(); $tax_exempt = $wc_customer->get_is_vat_exempt(); $calc = self::make_wdp_calc_from_wc(); $cart = self::make_wdp_cart_from_wc(); $newcart = $calc->process_cart_new( $cart ); if( $newcart ) { $newcart->apply_to_wc_cart(); } else { //try delete gifted products ? $wc_cart_items = WC()->cart->get_cart(); $cart_helper = new WDP_WC_Cart_Translator(); foreach ( $wc_cart_items as $wc_cart_item_key => $wc_cart_item ) { $wc_cart_item = apply_filters( 'wdp_wc_cart_item_before_clear_from_rules_keys', $wc_cart_item, $wc_cart_item_key ); $changed = false; if ( isset( $wc_cart_item['wdp_gifted'] ) ) { $wdp_gifted = $wc_cart_item['wdp_gifted']; unset( $wc_cart_item['wdp_gifted'] ); $changed = true; if ( $wdp_gifted ) { WC()->cart->remove_cart_item( $wc_cart_item_key ); continue; } } if ( isset( $wc_cart_item['wdp_original_price'] ) ) { unset( $wc_cart_item['wdp_original_price'] ); $changed = true; } if ( isset( $wc_cart_item['wdp_history'] ) ) { unset( $wc_cart_item['wdp_history'] ); $changed = true; } if ( isset( $wc_cart_item['wdp_rules'] ) ) { unset( $wc_cart_item['wdp_rules'] ); $changed = true; } if ( isset( $wc_cart_item[ WDP_Cart::INITIAL_DATA_KEY ] ) ) { unset( $wc_cart_item[ WDP_Cart::INITIAL_DATA_KEY ] ); $changed = true; } if ( isset( $wc_cart_item['rules'] ) ) { unset( $wc_cart_item['rules'] ); $changed = true; } if ( isset( $wc_cart_item['wdp_rules_for_singular'] ) ) { unset( $wc_cart_item['wdp_rules_for_singular'] ); $changed = true; } $product_id = $wc_cart_item['product_id']; $qty = $wc_cart_item['quantity']; $variation_id = $wc_cart_item['variation_id']; $variation = $wc_cart_item['variation']; $store_keys = apply_filters( 'wdp_save_cart_item_keys', array(), $cart_helper->get_external_keys( $wc_cart_item ) ); $cart_item_data = array(); foreach ( $store_keys as $key ) { if ( isset( $wc_cart_item[ $key ] ) ) { $cart_item_data[ $key ] = $wc_cart_item[ $key ]; } } if ( $changed ) { WC()->cart->remove_cart_item( $wc_cart_item_key ); $exclude_hooks = apply_filters('wdp_exclude_hooks_when_add_to_cart_after_disable_pricing', array(), $wc_cart_item); $key = self::process_without_hooks( function () use ( $product_id, $qty, $variation_id, $variation, $cart_item_data ) { return WC()->cart->add_to_cart( $product_id, $qty, $variation_id, $variation, $cart_item_data ); }, $exclude_hooks ); do_action( "wdp_restore_cart_item_hash", $key, $wc_cart_item, $wc_cart_item_key ); } } $is_free_shipping_key = '_wdp_free_shipping'; // clear shipping in session for triggering full calculate_shipping to replace '_wdp_free_shipping' when needed foreach ( WC()->session->get_session_data() as $key => $value ) { if ( preg_match( '/(shipping_for_package_).*/', $key, $matches ) === 1 ) { if ( ! isset( $matches[0] ) ) { continue; } $stored_rates = WC()->session->get( $matches[0] ); if ( ! isset( $stored_rates['rates'] ) ) { continue; } if ( is_array( $stored_rates['rates'] ) ) { foreach ( $stored_rates['rates'] as $rate ) { if ( isset( $rate->get_meta_data()[$is_free_shipping_key] ) ) { unset( WC()->session->$key ); break; } } } } } }// if no rules add_action( "woocommerce_before_calculate_totals", array( __CLASS__, "install_tax_exempt" ), 10, 1 ); add_action( "woocommerce_after_calculate_totals", array( __CLASS__, "uninstall_tax_exempt" ), 10, 1 ); self::set_rule_tax_exempt( $wc_customer->get_is_vat_exempt() ); $wc_customer->set_is_vat_exempt( $tax_exempt ); /** * fixed: Coupon could not be added! * We processing the cart AFTER 'set_session' call using hook. * So, we remove added coupons during wc-ajax. * Let do it manually. * * @see \WC_Cart_Session::init() */ ( new \WC_Cart_Session( WC()->cart ) )->set_session(); } /** * @return WDP_Cart_Calculator */ public static function make_wdp_calc_from_wc() { $rule_collection = WDP_Rules_Registry::get_instance()->get_active_rules(); $calc = WDP_Loader::get_cart_calculator_class( $rule_collection ); return $calc; } /** * @param bool $use_empty_cart * * @return WDP_Cart */ public static function make_wdp_cart_from_wc( $use_empty_cart = false ) { $context = self::make_wdp_cart_context_from_wc(); if ( ! ( WC()->cart instanceof WC_Cart ) ) { $use_empty_cart = true; } if ( $use_empty_cart ) { $cart = new WDP_Cart( $context ); } else { WDP_Cart::purge_wdp_coupons(); $cart = new WDP_Cart( $context, WC()->cart ); } return $cart; } /** * @return array */ private function get_wc_cart_coupons() { $external_coupons = array(); foreach ( WC()->cart->get_coupons() as $coupon ) { /** * @var $coupon WC_Coupon */ if ( $coupon->get_id() ) { $external_coupons[] = $coupon->get_code(); } } return $external_coupons; } /** * @return WDP_Cart_Context */ public static function make_wdp_cart_context_from_wc() { //test code $environment = array( 'timestamp' => current_time( 'timestamp' ), 'prices_includes_tax' => wc_prices_include_tax(), 'tab_enabled' => wc_tax_enabled(), 'tax_display_shop' => get_option( 'woocommerce_tax_display_shop' ), ); $settings = WDP_Helpers::get_settings(); if ( ! is_null( WC()->customer ) ) { $customer = new WDP_User_Impl( new WP_User( WC()->customer->get_id() ) ); $customer->set_shipping_country( WC()->customer->get_shipping_country( '' ) ); $customer->set_shipping_state( WC()->customer->get_shipping_state( '' ) ); $customer->set_is_vat_exempt( WC()->customer->get_is_vat_exempt() ); } else { $customer = new WDP_User_Impl( new WP_User() ); } if ( ! is_null( WC()->session ) ) { // todo is_checkout() and self::is_catalog_view() are too early when processing on 'wp_loaded' if ( is_checkout() ) $customer->set_payment_method( WC()->session->get('chosen_payment_method') ); if ( self::is_catalog_view() ) $customer->set_shipping_methods( WC()->session->get('chosen_shipping_methods') ); } $context = new WDP_Cart_Context( $customer, $environment, $settings ); return $context; } public function checkout_order_processed( $order_id, $posted_data, $order ) { list( $order_stats, $product_stats ) = $this->collect_wc_cart_stats( WC() ); $order_date = current_time( 'mysql' ); foreach ( $order_stats as $rule_id => $stats_item ) { $stats_item = array_merge( array( 'order_id' => $order_id, 'rule_id' => $rule_id, 'amount' => 0, 'extra' => 0, 'shipping' => 0, 'is_free_shipping' => 0, 'gifted_amount' => 0, 'gifted_qty' => 0, 'date' => $order_date, ), $stats_item ); WDP_Database::add_order_stats( $stats_item ); } foreach ( $product_stats as $product_id => $by_rule ) { foreach ( $by_rule as $rule_id => $stats_item ) { $stats_item = array_merge( array( 'order_id' => $order_id, 'product_id' => $product_id, 'rule_id' => $rule_id, 'qty' => 0, 'amount' => 0, 'gifted_amount' => 0, 'gifted_qty' => 0, 'date' => $order_date, ), $stats_item ); WDP_Database::add_product_stats( $stats_item ); } } } /** * @param WooCommerce $wc * * @return array */ private function collect_wc_cart_stats( $wc ) { $order_stats = array(); $product_stats = array(); $wc_cart = $wc->cart; $cart_items = $wc_cart->get_cart(); foreach ( $cart_items as $cart_item ) { $rules = isset( $cart_item['wdp_rules'] ) ? $cart_item['wdp_rules'] : ''; if ( empty( $rules ) ) { continue; } $product_id = $cart_item['product_id']; foreach ( $rules as $rule_id => $amount ) { //add stat rows if( !isset( $order_stats[ $rule_id ] ) ) { $order_stats[ $rule_id ] = array( 'amount'=>0, 'qty'=>0, 'gifted_qty'=>0, 'gifted_amount'=>0, 'shipping'=>0, 'is_free_shipping'=>0, 'extra'=>0 ); } if( !isset( $product_stats[ $product_id ][ $rule_id ] ) ) { $product_stats[ $product_id ][ $rule_id ] = array( 'amount'=>0, 'qty'=>0, 'gifted_qty'=>0, 'gifted_amount'=>0 ); } $prefix = !empty( $cart_item['wdp_gifted'] ) ? 'gifted_' : ""; // order $order_stats[ $rule_id ][ $prefix . 'qty' ] += $cart_item['quantity']; $order_stats[ $rule_id ][ $prefix . 'amount' ] += $amount * $cart_item['quantity']; // product $product_stats[ $product_id ][ $rule_id ][ $prefix . 'qty' ] += $cart_item['quantity']; $product_stats[ $product_id ][ $rule_id ][ $prefix . 'amount' ] += $amount * $cart_item['quantity']; } } $this->inject_wc_cart_coupon_stats( $wc_cart, $order_stats ); $this->inject_wc_cart_fee_stats( $wc_cart, $order_stats ); $this->inject_wc_cart_shipping_stats( $wc, $order_stats ); return array( $order_stats, $product_stats ); } /** * @param WC_Cart $wc_cart * @param array $order_stats */ private function inject_wc_cart_coupon_stats( $wc_cart, &$order_stats ) { $totals = $wc_cart->get_totals(); $wdp_coupons = isset( $totals['wdp_coupons'] ) ? $totals['wdp_coupons'] : array(); if ( empty( $wdp_coupons ) ) { return; } foreach ( $wc_cart->get_coupon_discount_totals() as $coupon_code => $amount ) { if ( isset( $wdp_coupons['grouped'][ $coupon_code ] ) ) { foreach ( $wdp_coupons['grouped'][ $coupon_code ] as $rule_id => $amount_per_rule ) { if ( ! isset( $order_stats[ $rule_id ] ) ) { $order_stats[ $rule_id ] = array(); } if ( ! isset( $order_stats[ $rule_id ]['extra'] ) ) { $order_stats[ $rule_id ]['extra'] = 0.0; } $order_stats[ $rule_id ]['extra'] += $amount_per_rule; } } elseif ( isset( $wdp_coupons['single'][ $coupon_code ] ) ) { $rule_id = $wdp_coupons['single'][ $coupon_code ]; if ( ! isset( $order_stats[ $rule_id ] ) ) { $order_stats[ $rule_id ] = array(); } if ( ! isset( $order_stats[ $rule_id ]['extra'] ) ) { $order_stats[ $rule_id ]['extra'] = 0.0; } $order_stats[ $rule_id ]['extra'] += $amount; } } } /** * @param WC_Cart $wc_cart * @param array $order_stats */ private function inject_wc_cart_fee_stats( $wc_cart, &$order_stats ) { $totals = $wc_cart->get_totals(); $wdp_fees = isset( $totals['wdp_fees'] ) ? $totals['wdp_fees'] : ''; if ( empty( $wdp_fees ) ) { return; } foreach ( $wc_cart->get_fees() as $fee ) { $fee_name = $fee->name; // change with care, reports are using fee->name too if ( isset( $wdp_fees[ $fee_name ] ) ) { foreach ( $wdp_fees[ $fee_name ] as $rule_id => $fee_amount_per_rule ) { $order_stats[ $rule_id ]['extra'] -= $fee_amount_per_rule; } } } } /** * @param WooCommerce $wc * @param array $order_stats */ private function inject_wc_cart_shipping_stats( $wc, &$order_stats ) { $shippings = $wc->session->get( 'chosen_shipping_methods' ); if ( empty( $shippings ) ) { return; } $applied_rules_key = '_wdp_rules'; $is_free_shipping_key = '_wdp_free_shipping'; foreach ( $shippings as $package_id => $shipping_rate_key ) { $packages = $wc->shipping()->get_packages(); if ( isset( $packages[ $package_id ]['rates'][ $shipping_rate_key ] ) ) { /** @var WC_Shipping_Rate $sh_rate */ $sh_rate = $packages[ $package_id ]['rates'][ $shipping_rate_key ]; $sh_rate_meta = $sh_rate->get_meta_data(); $is_free_shipping = isset( $sh_rate_meta[ $is_free_shipping_key ] ) ? $sh_rate_meta[ $is_free_shipping_key ] : false; $wdp_rules = isset( $sh_rate_meta[ $applied_rules_key ] ) ? json_decode( $sh_rate_meta[ $applied_rules_key ], true ) : false; if ( ! empty( $wdp_rules ) && is_array( $wdp_rules ) ) { foreach ( $wdp_rules as $rule_id => $amount ) { if ( ! isset( $order_stats[ $rule_id ] ) ) { $order_stats[ $rule_id ] = array(); } if ( ! isset( $order_stats[ $rule_id ]['shipping'] ) ) { $order_stats[ $rule_id ]['shipping'] = 0.0; } $order_stats[ $rule_id ]['shipping'] += $amount; $order_stats[ $rule_id ]['is_free_shipping'] = $is_free_shipping; } } } } } public static function wdp_get_template( $template_name , $args = array(), $template_path = '' ) { if ( ! empty( $args ) && is_array( $args ) ) { extract( $args ); } $full_template_path = trailingslashit( WC_ADP_PLUGIN_PATH . 'templates' ); if ( $template_path ) { $full_template_path .= trailingslashit( $template_path ); } $full_external_template_path = locate_template( array( 'advanced-dynamic-pricing-for-woocommerce/' . trailingslashit( $template_path ) . $template_name, 'advanced-dynamic-pricing-for-woocommerce/' . $template_name, ) ); if ( $full_external_template_path ) { $full_template_path = $full_external_template_path; } else { $full_template_path .= $template_name; } ob_start(); include $full_template_path; $template_content = ob_get_clean(); return $template_content; } public function load_frontend_assets() { $options = WDP_Helpers::get_settings(); wp_enqueue_style( 'wdp_pricing-table', WC_ADP_PLUGIN_URL . '/assets/css/pricing-table.css', array(), WC_ADP_VERSION ); wp_enqueue_style( 'wdp_deals-table', WC_ADP_PLUGIN_URL . '/assets/css/deals-table.css', array(), WC_ADP_VERSION ); if ( is_product() || woocommerce_product_loop() ) { wp_enqueue_script( 'wdp_deals', WC_ADP_PLUGIN_URL . '/assets/js/frontend.js', array(), WC_ADP_VERSION ); } if ( WDP_Database::is_condition_type_active( array( 'customer_shipping_method' ) ) ) { wp_enqueue_script( 'wdp_update_cart', WC_ADP_PLUGIN_URL . '/assets/js/update-cart.js' , array( 'wc-cart' ), WC_ADP_VERSION ); } $script_data = array( 'ajaxurl' => admin_url( 'admin-ajax.php' ), 'update_price_with_qty' => wc_string_to_bool( $options['update_price_with_qty'] ) && ! wc_string_to_bool( $options['do_not_modify_price_at_product_page'] ), 'js_init_trigger' => apply_filters( 'wdp_bulk_table_js_init_trigger', "" ), ); wp_localize_script( 'wdp_deals', 'script_data', $script_data ); } function remove_hooks_set_by_other_plugins() { global $wp_filter; $allowed_hooks = array( //Filters "woocommerce_get_price_html" => array( "WDP_Price_Display|hook_get_price_html" ), "woocommerce_product_is_on_sale" => array( "WDP_Price_Display|hook_product_is_on_sale" ), "woocommerce_product_get_sale_price" => array( "WDP_Price_Display|hook_product_get_sale_price" ), "woocommerce_product_get_regular_price" => array( "WDP_Price_Display|hook_product_get_regular_price" ), "woocommerce_variable_price_html" => array(), "woocommerce_variable_sale_price_html" => array(), "woocommerce_cart_item_price" => array( "WDP_Price_Display|woocommerce_cart_item_price_and_price_subtotal" ), "woocommerce_cart_item_subtotal" => array( "WDP_Price_Display|woocommerce_cart_item_price_and_price_subtotal" ), //Actions "woocommerce_checkout_order_processed" => array( "WDP_Frontend|checkout_order_processed" ), "woocommerce_before_calculate_totals" => array(), //nothing allowed! ); foreach ( $wp_filter as $hook_name => $hook_obj ) { if ( preg_match( '#^woocommerce_#', $hook_name ) ) { if ( isset( $allowed_hooks[ $hook_name ] ) ) { $wp_filter[ $hook_name ] = $this->remove_wrong_callbacks( $hook_obj, $allowed_hooks[ $hook_name ] ); } else { } } } } public static function remove_callbacks( $hook_obj, $hooks ) { $new_callbacks = array(); foreach ( $hook_obj->callbacks as $priority => $callbacks ) { $priority_callbacks = array(); foreach ( $callbacks as $idx => $callback_details ) { if ( ! self::is_callback_match( $callback_details, $hooks ) ) { $priority_callbacks[ $idx ] = $callback_details; } } if ( $priority_callbacks ) { $new_callbacks[ $priority ] = $priority_callbacks; } } $hook_obj->callbacks = $new_callbacks; return $hook_obj; } function remove_wrong_callbacks( $hook_obj, $allowed_hooks ) { $new_callbacks = array(); foreach ( $hook_obj->callbacks as $priority => $callbacks ) { $priority_callbacks = array(); foreach ( $callbacks as $idx => $callback_details ) { if ( self::is_callback_match( $callback_details, $allowed_hooks ) ) { $priority_callbacks[ $idx ] = $callback_details; } } if ( $priority_callbacks ) { $new_callbacks[ $priority ] = $priority_callbacks; } } $hook_obj->callbacks = $new_callbacks; return $hook_obj; } //check class + function name! public static function is_callback_match( $callback_details, $allowed_hooks ) { // we add our hooks as Class:member, so "function" will be array and will have 2 elements! if ( !is_array($callback_details['function']) OR count( $callback_details['function'] ) != 2 ) { return false; // not our hook! } $callback_obj = $callback_details['function'][0]; $callback_func = $callback_details['function'][1]; if ( is_object( $callback_obj ) ) { $callback_class = get_class( $callback_obj ); } elseif ( is_string( $callback_obj ) && class_exists( $callback_obj ) ) { $callback_class = $callback_obj; } else { return false; // definitely not ours } $result = false; foreach ( $allowed_hooks as $callback_name ) { list( $class_name, $func_name ) = explode( "|", $callback_name ); if ( $class_name == $callback_class AND $func_name == $callback_func ) { $result = true; break;// don't remove own hooks! } } return $result; } private $last_variation = array(); private $last_variation_hash = array(); /** * The only way to snatch $variation before woocommerce_add_to_cart_sold_individually_found_in_cart() * * @param string $hash * @param int $product_id * @param int $variation_id * @param array $variation * @param array $cart_item_data * * @return string */ public function woocommerce_cart_id( $hash, $product_id, $variation_id, $variation, $cart_item_data) { $this->last_variation = $variation; $this->last_variation_hash = $hash; return $hash; } public function woocommerce_add_to_cart_sold_individually_found_in_cart( $found, $product_id, $variation_id, $cart_item_data, $cart_id ) { // already found in cart if ( $found ) { return true; } $variation = array(); if ( $this->last_variation_hash && $this->last_variation_hash === $cart_id ) { $variation = $this->last_variation; } $wdp_keys = array( 'wdp_rules', 'wdp_gifted', 'wdp_original_price', WDP_Cart::INITIAL_DATA_KEY, ); $cart_item_data = array_filter( $cart_item_data, function ( $key ) use ( $wdp_keys ) { return ! in_array( $key, $wdp_keys ); }, ARRAY_FILTER_USE_KEY ); $no_pricing_cart_id = WC()->cart->generate_cart_id( $product_id, $variation_id, $variation, $cart_item_data ); if ( ! $no_pricing_cart_id ) { return $found; } foreach ( WC()->cart->get_cart() as $cart_item ) { if ( $no_pricing_cart_id === $this->calculate_cart_item_hash_without_pricing( $cart_item ) ) { return true; } } return $found; } private function calculate_cart_item_hash_without_pricing( $cart_item_data ) { $product_id = isset( $cart_item_data['product_id'] ) ? $cart_item_data['product_id'] : 0; if ( ! $product_id ) { return false; } $variation_id = isset( $cart_item_data['variation_id'] ) ? $cart_item_data['variation_id'] : 0; $variation = isset( $cart_item_data['variation'] ) ? $cart_item_data['variation'] : array(); $wdp_keys = array( 'wdp_rules', 'wdp_gifted', 'wdp_original_price', ); $default_keys = array( 'key', 'product_id', 'variation_id', 'variation', 'quantity', 'data', 'data_hash', 'line_tax_data', 'line_subtotal', 'line_subtotal_tax', 'line_total', 'line_tax', ); $cart_item_data = array_filter( $cart_item_data, function ( $key ) use ( $wdp_keys, $default_keys ) { return ! in_array( $key, array_merge( $wdp_keys, $default_keys ) ); }, ARRAY_FILTER_USE_KEY ); return WC()->cart->generate_cart_id( $product_id, $variation_id, $variation, $cart_item_data ); } private static function get_nopriv_ajax_actions() { return array( 'get_table_with_product_bulk_table', 'get_price_product_with_bulk_table', ); } private static function get_ajax_actions() { return array_merge( self::get_nopriv_ajax_actions(), self::get_priv_ajax_actions() ); } private static function get_priv_ajax_actions() { return array( 'download_report', 'get_user_report_data', ); } public static function is_ajax_processing() { return wp_doing_ajax() && ! empty( $_REQUEST['action'] ) && in_array( $_REQUEST['action'], self::get_ajax_actions() ); } public static function get_gifted_cart_products() { return WDP_Functions::get_gifted_cart_products(); } public static function get_active_rules_for_product( $product_id, $qty = 1, $use_empty_cart = false ) { return WDP_Functions::get_active_rules_for_product( $product_id, $qty, $use_empty_cart ); } public static function get_discounted_products_for_cart( $array_of_products, $plain = false ) { return WDP_Functions::get_discounted_products_for_cart( $array_of_products, $plain ); } public static function get_discounted_product_price( $the_product, $qty, $use_empty_cart = true ) { return WDP_Functions::get_discounted_product_price( $the_product, $qty, $use_empty_cart ); } public static function process_without_hooks( $callback, $hooks_list ) { return WDP_Functions::process_without_hooks( $callback, $hooks_list ); } protected static function clearWcCartItems() { foreach ( WC()->cart->get_cart_contents() as $wc_cart_item ) { $product = $wc_cart_item['data']; try { $reflection = new ReflectionClass( $product ); $property = $reflection->getProperty( 'changes' ); $property->setAccessible( true ); $property->setValue( $product, array() ); } catch ( Exception $e ) { } $wc_cart_item['data'] = $product; } $default_keys = array( 'key', 'product_id', 'variation_id', 'variation', 'quantity', 'data', 'data_hash', 'line_tax_data', 'line_subtotal', 'line_subtotal_tax', 'line_total', 'line_tax', ); $newItems = array(); foreach ( WC()->cart->cart_contents as $cartKey => $wcCartItem ) { $cartItemData = array(); $product_id = $wcCartItem['product_id']; $variation_id = $wcCartItem['variation_id']; $variation = $wcCartItem['variation']; if ( ! isset($wcCartItem['wdp_gifted']) ) { unset( $wcCartItem['wdp_rules'] ); } unset( $wcCartItem['wdp_original_price'] ); unset( $wcCartItem[ WDP_Cart::INITIAL_DATA_KEY ] ); foreach ( $wcCartItem as $key => $value ) { if ( ! in_array( $key, $default_keys ) ) { $cartItemData[ $key ] = $value; } } $cart_id = WC()->cart->generate_cart_id( $product_id, $variation_id, $variation, $cartItemData ); $wcCartItem['key'] = $cart_id; if ( isset( $newItems[ $cart_id ] ) ) { $newItems[ $cart_id ]['quantity'] += $wcCartItem['quantity']; } else { $newItems[ $cart_id ] = $wcCartItem; } } WC()->cart->cart_contents = $newItems; WDP_Frontend::process_without_hooks( function () { WC()->cart->calculate_totals(); }, array( 'woocommerce_after_calculate_totals' ) ); } }