includes();
add_action( 'plugins_loaded', array( $this, 'load_action_scheduler' ), -1 );
add_action( 'init', array( $this, 'process_activation' ) );
add_action( 'init', array( $this, 'add_sc_options' ) );
add_action( 'init', array( $this, 'define_label_for_store_credit' ) );
add_filter( 'woocommerce_coupon_is_valid', array( $this, 'is_smart_coupon_valid' ), 10, 3 );
add_filter( 'woocommerce_coupon_is_valid', array( $this, 'is_user_usage_limit_valid' ), 10, 3 );
add_filter( 'woocommerce_coupon_is_valid_for_product', array( $this, 'smart_coupons_is_valid_for_product' ), 10, 4 );
add_filter( 'woocommerce_coupon_validate_expiry_date', array( $this, 'validate_expiry_time' ), 999, 3 );
add_filter( 'woocommerce_apply_individual_use_coupon', array( $this, 'smart_coupons_override_individual_use' ), 10, 3 );
add_filter( 'woocommerce_apply_with_individual_use_coupon', array( $this, 'smart_coupons_override_with_individual_use' ), 10, 4 );
add_action( 'restrict_manage_posts', array( $this, 'woocommerce_restrict_manage_smart_coupons' ), 20 );
add_action( 'admin_init', array( $this, 'woocommerce_export_coupons' ) );
add_action( 'personal_options_update', array( $this, 'my_profile_update' ) );
add_action( 'edit_user_profile_update', array( $this, 'my_profile_update' ) );
add_filter( 'generate_smart_coupon_action', array( $this, 'generate_smart_coupon_action' ), 1, 10 );
add_action( 'wc_sc_new_coupon_generated', array( $this, 'smart_coupons_plugin_used' ) );
// Actions used to insert a new endpoint in the WordPress.
add_action( 'init', array( $this, 'sc_add_endpoints' ), 11 );
add_action( 'admin_enqueue_scripts', array( $this, 'smart_coupon_styles_and_scripts' ), 20 );
add_action( 'admin_enqueue_scripts', array( $this, 'register_plugin_styles' ) );
add_action( 'wp_enqueue_scripts', array( $this, 'register_plugin_styles' ) );
add_filter( 'wc_smart_coupons_export_headers', array( $this, 'wc_smart_coupons_export_headers' ) );
add_filter( 'woocommerce_email_footer_text', array( $this, 'email_footer_replace_site_title' ) );
add_filter( 'is_protected_meta', array( $this, 'make_sc_meta_protected' ), 10, 3 );
add_action( 'admin_notices', array( $this, 'minimum_woocommerce_version_requirement' ) );
add_action( 'wp_loaded', array( $this, 'sc_handle_store_credit_application' ), 15 );
add_filter( 'woocommerce_debug_tools', array( $this, 'clear_cache_tool' ) );
add_action( 'woocommerce_checkout_update_order_review', array( $this, 'woocommerce_checkout_update_order_review' ) );
add_action( 'woocommerce_cart_reset', array( $this, 'woocommerce_cart_reset' ) );
// Actions used to schedule sending of coupons.
add_action( 'wc_sc_send_scheduled_coupon_email', array( $this, 'send_scheduled_coupon_email' ), 10, 7 );
add_action( 'wc_sc_import_send_scheduled_coupon_email', array( $this, 'import_send_scheduled_coupon_email' ), 10, 5 );
add_action( 'publish_future_post', array( $this, 'process_published_scheduled_coupon' ) );
add_action( 'before_delete_post', array( $this, 'delete_scheduled_coupon_actions' ) );
add_action( 'admin_footer', array( $this, 'enqueue_admin_footer_scripts' ) );
add_action( 'wp_ajax_wc_sc_check_scheduled_coupon_actions', array( $this, 'check_scheduled_coupon_actions' ) );
// Filter to modify discount amount for percentage type coupon.
add_filter( 'woocommerce_coupon_get_discount_amount', array( $this, 'get_coupon_discount_amount' ), 10, 5 );
// Filter to add default values to coupon meta fields.
add_filter( 'smart_coupons_parser_postmeta_defaults', array( $this, 'postmeta_defaults' ) );
// Filter to register Smart Coupons' email classes.
add_filter( 'woocommerce_email_classes', array( $this, 'register_email_classes' ) );
add_filter( 'woocommerce_hold_stock_for_checkout', array( $this, 'hold_stock_for_checkout' ) );
add_action( 'wc_sc_generate_coupon', array( $this, 'generate_coupon' ) );
add_action( 'wc_sc_paint_coupon', array( $this, 'paint_coupon' ) );
add_filter( 'woocommerce_rest_api_get_rest_namespaces', array( $this, 'rest_namespace' ) );
add_filter( 'woocommerce_shipping_free_shipping_is_available', array( $this, 'is_eligible_for_free_shipping' ), 10, 3 );
add_action( 'woocommerce_system_status_report', array( $this, 'smart_coupons_system_status_report' ), 11 );
add_action( 'woocommerce_rest_prepare_shop_order_object', array( $this, 'rest_api_prepare_shop_order_object' ), 10, 3 );
add_action( 'before_woocommerce_init', array( $this, 'hpos_compat_declaration' ) );
add_action( 'before_woocommerce_init', array( $this, 'blocks_compat_declaration' ) );
add_filter( 'woocommerce_order_item_get_formatted_meta_data', array( $this, 'format_sc_meta_data' ), 99, 2 );
add_filter( 'woocommerce_hidden_order_itemmeta', array( $this, 'hidden_order_itemmeta' ) );
add_filter( 'woocommerce_order_data_store_cpt_get_orders_query', array( $this, 'custom_meta_support_in_orders_query' ), 10, 2 );
add_action( 'upgrader_process_complete', array( $this, 'upgrader_process_complete' ), 10, 2 );
add_action( 'woocommerce_remove_cart_item', array( $this, 'sc_remove_coupon_with_cart_item' ), 10, 2 );
add_action( 'woocommerce_blocks_loaded', array( $this, 'register_endpoint_data' ) );
add_action( 'woocommerce_store_api_checkout_update_order_from_request', array( $this, 'save_coupon_receiver_detail_in_order' ), 10, 2 );
add_action( 'woocommerce_order_after_calculate_totals', array( $this, 'update_smart_coupon_order_create_via_admin' ), 99, 2 );
}
/**
* Function to handle WC compatibility related function call from appropriate class
*
* @param string $function_name Function to call.
* @param array $arguments Array of arguments passed while calling $function_name.
* @return mixed Result of function call.
*/
public function __call( $function_name, $arguments = array() ) {
if ( ! is_callable( 'SA_WC_Compatibility_8_7', $function_name ) ) {
return;
}
if ( ! empty( $arguments ) ) {
return call_user_func_array( 'SA_WC_Compatibility_8_7::' . $function_name, $arguments );
} else {
return call_user_func( 'SA_WC_Compatibility_8_7::' . $function_name );
}
}
/**
* Include files
*/
public function includes() {
include_once 'compat/class-sa-wc-compatibility-4-4.php';
include_once 'compat/class-sa-wc-compatibility-8-7.php';
include_once 'compat/class-wc-sc-wpml-compatibility.php';
include_once 'compat/class-wcopc-sc-compatibility.php';
include_once 'compat/class-wcs-sc-compatibility.php';
include_once 'compat/class-wc-sc-wmc-compatibility.php';
include_once 'compat/class-wc-sc-aelia-cs-compatibility.php';
include_once 'compat/class-wc-sc-kco-compatibility.php';
include_once 'compat/class-wc-sc-pnr-compatibility.php';
include_once 'compat/class-wc-sc-wscp-compatibility.php';
include_once 'class-wc-sc-admin-welcome.php';
include_once 'class-wc-sc-background-coupon-importer.php';
include_once 'class-wc-sc-admin-pages.php';
include_once 'class-wc-sc-admin-notifications.php';
include_once 'class-wc-sc-ajax.php';
include_once 'class-wc-sc-display-coupons.php';
include_once 'class-wc-sc-settings.php';
include_once 'class-wc-sc-shortcode.php';
include_once 'class-wc-sc-purchase-credit.php';
include_once 'class-wc-sc-url-coupon.php';
include_once 'class-wc-sc-print-coupon.php';
include_once 'class-wc-sc-coupon-fields.php';
include_once 'class-wc-sc-auto-apply-coupon.php';
include_once 'class-wc-sc-product-fields.php';
include_once 'class-wc-sc-order-fields.php';
include_once 'class-wc-sc-coupon-process.php';
include_once 'class-wc-sc-global-coupons.php';
include_once 'class-wc-sc-admin-coupons-dashboard-actions.php';
include_once 'class-wc-sc-privacy.php';
include_once 'class-wc-sc-coupon-actions.php';
include_once 'class-wc-sc-coupon-columns.php';
include_once 'class-wc-sc-product-columns.php';
include_once 'class-wc-sc-coupons-by-location.php';
include_once 'class-wc-sc-coupons-by-payment-method.php';
include_once 'class-wc-sc-coupons-by-shipping-method.php';
include_once 'class-wc-sc-coupons-by-user-role.php';
include_once 'class-wc-sc-coupons-by-product-attribute.php';
include_once 'class-wc-sc-coupons-by-taxonomy.php';
include_once 'class-wc-sc-coupons-by-excluded-email.php';
include_once 'class-wc-sc-coupon-message.php';
include_once 'class-wc-sc-coupon-categories.php';
include_once 'class-wc-sc-coupons-by-product-quantity.php';
include_once 'class-wc-sc-coupon-refund-process.php';
include_once 'class-wc-sc-background-upgrade.php';
include_once 'blocks/class-wc-sc-gutenberg-coupon-block.php';
}
/**
* Process activation of the plugin
*/
public function process_activation() {
if ( ! get_transient( '_smart_coupons_process_activation' ) ) {
return;
}
delete_transient( '_smart_coupons_process_activation' );
include_once 'class-wc-sc-act-deact.php';
WC_SC_Act_Deact::process_activation();
}
/**
* Load action scheduler
*/
public function load_action_scheduler() {
if ( ! class_exists( 'ActionScheduler' ) ) {
include_once 'libraries/action-scheduler/action-scheduler.php';
}
}
/**
* Set options
*/
public function add_sc_options() {
$this->plugin_data = self::get_smart_coupons_plugin_data();
add_option( 'woocommerce_delete_smart_coupon_after_usage', 'no', '', 'no' );
add_option( 'woocommerce_smart_coupon_apply_before_tax', 'no', '', 'no' );
add_option( 'woocommerce_smart_coupon_include_tax', 'no', '', 'no' );
add_option( 'woocommerce_smart_coupon_show_my_account', 'yes', '', 'no' );
add_option( 'smart_coupons_is_show_associated_coupons', 'no', '', 'no' );
add_option( 'smart_coupons_show_coupon_description', 'no', '', 'no' );
add_option( 'smart_coupons_is_send_email', 'yes', '', 'no' );
add_option( 'smart_coupons_is_print_coupon', 'yes', '', 'no' );
add_option( 'show_coupon_received_on_my_account', 'no', '', 'no' );
add_option( 'pay_from_smart_coupon_of_original_order', 'yes', '', 'no' );
add_option( 'stop_recursive_coupon_generation', 'no', '', 'no' );
add_option( 'sc_gift_certificate_shop_loop_button_text', __( 'Select options', 'woocommerce-smart-coupons' ), '', 'no' );
add_option( 'wc_sc_setting_max_coupon_to_show', '5', '', 'no' );
add_option( 'smart_coupons_show_invalid_coupons_on_myaccount', 'no', '', 'no' );
add_option( 'smart_coupons_sell_store_credit_at_less_price', 'no', '', 'no' );
add_option( 'smart_coupons_display_coupon_receiver_details_form', 'yes', '', 'no' );
// Convert SC admin email settings into WC email settings.
$is_send_email = get_option( 'smart_coupons_is_send_email' );
if ( false !== $is_send_email ) {
$coupon_email_settings = get_option( 'woocommerce_wc_sc_email_coupon_settings' );
if ( false === $coupon_email_settings ) {
$coupon_email_settings = array();
$coupon_email_settings['enabled'] = $is_send_email;
update_option( 'woocommerce_wc_sc_email_coupon_settings', $coupon_email_settings, 'no' );
}
}
$is_combine_email = get_option( 'smart_coupons_combine_emails' );
if ( false !== $is_combine_email ) {
$combine_email_settings = get_option( 'woocommerce_wc_sc_combined_email_coupon_settings' );
if ( false === $combine_email_settings ) {
$combine_email_settings = array();
$combine_email_settings['enabled'] = $is_combine_email;
update_option( 'woocommerce_wc_sc_combined_email_coupon_settings', $combine_email_settings, 'no' );
}
}
$valid_designs = $this->get_valid_coupon_designs();
$coupon_design = get_option( 'wc_sc_setting_coupon_design' );
if ( false === $coupon_design ) {
add_option( 'wc_sc_setting_coupon_design', 'basic', '', 'no' );
} else {
if ( 'custom-design' !== $coupon_design && ! in_array( $coupon_design, $valid_designs, true ) ) {
update_option( 'wc_sc_setting_coupon_design', 'basic', 'no' );
}
}
$coupon_background_color = get_option( 'wc_sc_setting_coupon_background_color' );
if ( false === $coupon_background_color ) {
add_option( 'wc_sc_setting_coupon_background_color', '#2b2d42', '', 'no' );
} else {
add_option( 'wc_sc_setting_coupon_third_color', $coupon_background_color, '', 'no' );
}
$coupon_foreground_color = get_option( 'wc_sc_setting_coupon_foreground_color' );
if ( false === $coupon_foreground_color ) {
add_option( 'wc_sc_setting_coupon_foreground_color', '#edf2f4', '', 'no' );
}
$coupon_third_color = get_option( 'wc_sc_setting_coupon_third_color' );
if ( false === $coupon_third_color ) {
add_option( 'wc_sc_setting_coupon_third_color', '#d90429', '', 'no' );
}
$coupon_design_colors = get_option( 'wc_sc_setting_coupon_design_colors' );
if ( false === $coupon_design_colors ) {
if ( false !== $coupon_background_color && false !== $coupon_foreground_color ) {
add_option( 'wc_sc_setting_coupon_design_colors', 'custom', '', 'no' );
} else {
add_option( 'wc_sc_setting_coupon_design_colors', '2b2d42-edf2f4-d90429', '', 'no' );
}
}
$coupon_design_for_email = get_option( 'wc_sc_setting_coupon_design_for_email' );
if ( false === $coupon_design_for_email ) {
add_option( 'wc_sc_setting_coupon_design_for_email', 'email-coupon', '', 'no' );
}
$orders_prior_to_800 = $this->sc_get_option( 'wc_sc_old_orders_prior_to_800' );
if ( false === $orders_prior_to_800 ) {
$this->maybe_sync_orders_prior_to_800();
}
}
/**
* Function to log messages generated by Smart Coupons plugin
*
* @param string $level Message type. Valid values: debug, info, notice, warning, error, critical, alert, emergency.
* @param string $message The message to log.
*/
public function log( $level = 'notice', $message = '' ) {
if ( empty( $message ) ) {
return;
}
if ( function_exists( 'wc_get_logger' ) ) {
$logger = wc_get_logger();
$context = array( 'source' => 'woocommerce-smart-coupons' );
$logger->log( $level, $message, $context );
} else {
include_once plugin_dir_path( WC_PLUGIN_FILE ) . 'includes/class-wc-logger.php';
$logger = new WC_Logger();
$logger->add( 'woocommerce-smart-coupons', $message );
}
}
/**
* Coupon's expiration date (formatted)
*
* @param int $expiry_date Expiry date of coupon.
* @return string $expires_string Formatted expiry date
*/
public function get_expiration_format( $expiry_date ) {
if ( $this->is_wc_gte_30() && $expiry_date instanceof WC_DateTime ) {
$expiry_date = ( is_callable( array( $expiry_date, 'getTimestamp' ) ) ) ? $expiry_date->getTimestamp() : null;
} elseif ( ! is_int( $expiry_date ) ) {
$expiry_date = $this->strtotime( $expiry_date );
}
$expiry_date += $this->wc_timezone_offset();
$expires_string = date_i18n( get_option( 'date_format', 'd-M-Y' ), $expiry_date );
return apply_filters(
'wc_sc_formatted_coupon_expiry_date',
$expires_string,
array(
'source' => $this,
'expiry_date' => $expiry_date,
)
);
}
/**
* Function to send e-mail containing coupon code to receiver
*
* @param array $coupon_title Associative array containing receiver's details.
* @param string $discount_type Type of coupon.
* @param int $order_id Associated order id.
* @param array $gift_certificate_receiver_name Array of receiver's name.
* @param string $message_from_sender Message added by sender.
* @param string $gift_certificate_sender_name Sender name.
* @param string $gift_certificate_sender_email Sender email.
* @param boolean $is_gift Whether it is a gift certificate or store credit.
*/
public function sa_email_coupon( $coupon_title, $discount_type, $order_id = '', $gift_certificate_receiver_name = '', $message_from_sender = '', $gift_certificate_sender_name = '', $gift_certificate_sender_email = '', $is_gift = '' ) {
$is_send_email = $this->is_email_template_enabled();
$combine_emails = $this->is_email_template_enabled( 'combine' );
if ( 'yes' === $is_send_email ) {
WC()->mailer();
}
$is_send_email = apply_filters(
'wc_sc_is_send_coupon_email',
$is_send_email,
array(
'source' => $this,
'coupon_title' => $coupon_title,
'discount_type' => $discount_type,
'order_id' => $order_id,
'gift_certificate_receiver_name' => $gift_certificate_receiver_name,
'message_from_sender' => $message_from_sender,
'gift_certificate_sender_name' => $gift_certificate_sender_name,
'gift_certificate_sender_email' => $gift_certificate_sender_email,
'is_gift' => $is_gift,
)
);
$order = ( ! empty( $order_id ) ) ? wc_get_order( $order_id ) : null;
foreach ( $coupon_title as $email => $coupon ) {
if ( empty( $email ) ) {
$email = $gift_certificate_sender_email;
}
$amount = $coupon['amount'];
$coupon_code = strtolower( $coupon['code'] );
if ( ! empty( $order_id ) ) {
$coupon_receiver_details = $this->get_post_meta( $order_id, 'sc_coupon_receiver_details', true, false, $order );
if ( ! is_array( $coupon_receiver_details ) || empty( $coupon_receiver_details ) ) {
$coupon_receiver_details = array();
}
$coupon_receiver_details[] = array(
'code' => $coupon_code,
'amount' => $amount,
'email' => $email,
'message' => $message_from_sender,
);
$this->update_post_meta( $order_id, 'sc_coupon_receiver_details', $coupon_receiver_details, false, $order );
}
$action_args = apply_filters(
'wc_sc_email_coupon_notification_args',
array(
'order_id' => $order_id,
'email' => $email,
'coupon' => $coupon,
'discount_type' => $discount_type,
'receiver_name' => $gift_certificate_receiver_name,
'message_from_sender' => $message_from_sender,
'gift_certificate_sender_name' => $gift_certificate_sender_name,
'gift_certificate_sender_email' => $gift_certificate_sender_email,
'is_gift' => $is_gift,
)
);
$schedule_gift_sending = 'no';
if ( ! empty( $order_id ) ) {
$schedule_gift_sending = ( $this->is_callable( $order, 'get_meta' ) ) ? $order->get_meta( 'wc_sc_schedule_gift_sending' ) : $this->get_post_meta( $order_id, 'wc_sc_schedule_gift_sending', true );
}
$is_schedule_gift_sending = 'no';
if ( 'yes' === $schedule_gift_sending ) {
$coupon_id = wc_get_coupon_id_by_code( $coupon_code );
$coupon_receiver_details = $this->get_post_meta( $coupon_id, 'wc_sc_coupon_receiver_details', true );
$scheduled_coupon_code = ( ! empty( $coupon_receiver_details['coupon_details']['code'] ) ) ? strtolower( $coupon_receiver_details['coupon_details']['code'] ) : '';
if ( $scheduled_coupon_code === $coupon_code ) {
$is_schedule_gift_sending = 'yes';
}
}
if ( 'yes' === $is_send_email && ( 'no' === $combine_emails || 'yes' === $is_schedule_gift_sending ) ) {
$current_filter = current_filter();
$order_actions_to_ignore_for_email = $this->order_actions_to_ignore_for_email();
if ( ! in_array( $current_filter, $order_actions_to_ignore_for_email, true ) ) {
// Trigger email notification.
do_action( 'wc_sc_email_coupon_notification', $action_args );
}
if ( 'yes' === $is_schedule_gift_sending ) {
// Delete receiver detail post meta as it is no longer necessary.
$this->delete_post_meta( $coupon_id, 'wc_sc_coupon_receiver_details' );
}
}
}
}
/**
* Function to send combined e-mail containing coupon codes to receiver
*
* @param string $receiver_email receiver's email.
* @param array $receiver_details receiver details(code,message etc).
* @param int $order_id Associated order id.
* @param string $gift_certificate_sender_name Sender name.
* @param string $gift_certificate_sender_email Sender email.
*/
public function send_combined_coupon_email( $receiver_email = '', $receiver_details = array(), $order_id = 0, $gift_certificate_sender_name = '', $gift_certificate_sender_email = '' ) {
$is_send_email = $this->is_email_template_enabled();
$combine_emails = $this->is_email_template_enabled( 'combine' );
if ( 'yes' === $is_send_email && 'yes' === $combine_emails ) {
$current_filter = current_filter();
$order_actions_to_ignore_for_email = $this->order_actions_to_ignore_for_email();
if ( ! in_array( $current_filter, $order_actions_to_ignore_for_email, true ) ) {
WC()->mailer();
$order = ( ! empty( $order_id ) ) ? wc_get_order( $order_id ) : null;
$is_gift = '';
if ( ! empty( $order_id ) ) {
$is_gift = $this->get_post_meta( $order_id, 'is_gift', true );
}
if ( count( $receiver_details ) === 1 ) {
$coupon_code = ( ! empty( $receiver_details[0]['code'] ) ) ? $receiver_details[0]['code'] : '';
$message_from_sender = ( ! empty( $receiver_details[0]['message'] ) ) ? $receiver_details[0]['message'] : '';
$coupon = new WC_Coupon( $coupon_code );
$coupon_amount = $this->get_amount( $coupon, true, $order );
$discount_type = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_discount_type' ) ) ) ? $coupon->get_discount_type() : '';
$coupon_data = $this->get_coupon_meta_data( $coupon );
$coupon_detail = array(
'amount' => $coupon_amount,
'code' => $coupon_code,
);
$action_args = apply_filters(
'wc_sc_email_coupon_notification_args',
array(
'order_id' => $order_id,
'email' => $receiver_email,
'coupon' => $coupon_detail,
'discount_type' => $discount_type,
'receiver_name' => '',
'message_from_sender' => $message_from_sender,
'gift_certificate_sender_name' => $gift_certificate_sender_name,
'gift_certificate_sender_email' => $gift_certificate_sender_email,
'is_gift' => $is_gift,
)
);
// Trigger single email notification.
do_action( 'wc_sc_email_coupon_notification', $action_args );
return;
}
}
$action_args = apply_filters(
'wc_sc_email_coupon_notification_args',
array(
'order_id' => $order_id,
'email' => $receiver_email,
'receiver_details' => $receiver_details,
'gift_certificate_sender_name' => $gift_certificate_sender_name,
'gift_certificate_sender_email' => $gift_certificate_sender_email,
'is_gift' => $is_gift,
)
);
// Trigger combined email notification.
do_action( 'wc_sc_combined_email_coupon_notification', $action_args );
}
}
/**
* Function to schedule e-mail sending process containing coupon code to customer
*
* @param array $action_args arguments for Action Scheduler.
* @param string $sending_timestamp timestamp for scheduling email.
* @return boolean email sending scheduled or not.
*/
public function schedule_coupon_email( $action_args = array(), $sending_timestamp = '' ) {
if ( empty( $action_args ) || empty( $sending_timestamp ) ) {
return false;
}
$coupon_id = 0;
if ( isset( $action_args['coupon_id'] ) && ! empty( $action_args['coupon_id'] ) ) {
$coupon_id = $action_args['coupon_id'];
}
$ref_key = '';
if ( isset( $action_args['ref_key'] ) && ! empty( $action_args['ref_key'] ) ) {
$ref_key = $action_args['ref_key'];
}
if ( ! empty( $coupon_id ) && ! empty( $ref_key ) && function_exists( 'as_schedule_single_action' ) ) {
if ( ! empty( $action_args['order_id'] ) ) {
$actions_id = as_schedule_single_action( $sending_timestamp, 'wc_sc_send_scheduled_coupon_email', $action_args );
} else {
$actions_id = as_schedule_single_action( $sending_timestamp, 'wc_sc_import_send_scheduled_coupon_email', $action_args );
}
if ( $actions_id ) {
$scheduled_actions_ids = $this->get_post_meta( $coupon_id, 'wc_sc_scheduled_actions_ids', true );
if ( empty( $scheduled_actions_ids ) || ! is_array( $scheduled_actions_ids ) ) {
$scheduled_actions_ids = array();
}
$scheduled_actions_ids[ $ref_key ] = $actions_id;
// Stored actions ids in coupons so that we can delete them when coupon gets deleted or email is sent successfully.
$this->update_post_meta( $coupon_id, 'wc_sc_scheduled_actions_ids', $scheduled_actions_ids );
return true;
}
}
return false;
}
/**
* Function to send scheduled coupon's e-mail containing coupon code to receiver. It is triggered through Action Scheduler
*
* @param string $auto_generate is auto generated coupon.
* @param int $coupon_id Associated coupon id.
* @param int $parent_id Associated parent coupon id.
* @param int $order_id Associated order id.
* @param string $receiver_email receiver email.
* @param string $sender_message_index_key key containing index of sender's message from gift_receiver_message meta in order.
* @param string $ref_key timestamp based reference key.
*/
public function send_scheduled_coupon_email( $auto_generate = '', $coupon_id = '', $parent_id = '', $order_id = '', $receiver_email = '', $sender_message_index_key = '', $ref_key = '' ) {
if ( ! empty( $coupon_id ) && ! empty( $order_id ) && ! empty( $receiver_email ) ) {
$coupon = new WC_Coupon( $coupon_id );
$coupon_status = ( $this->is_wc_greater_than( '6.1.2' ) && $this->is_callable( $coupon, 'get_status' ) ) ? $coupon->get_status() : get_post_status( $coupon_id );
if ( 'publish' !== $coupon_status ) {
return;
}
$order = wc_get_order( $order_id );
if ( is_a( $coupon, 'WC_Coupon' ) && is_a( $order, 'WC_Order' ) ) {
$is_callable_order_get_meta = $this->is_callable( $order, 'get_meta' );
$is_callable_coupon_get_meta = $this->is_callable( $coupon, 'get_meta' );
$is_callable_coupon_update_meta_data = $this->is_callable( $coupon, 'update_meta_data' );
$sc_disable_email_restriction = $this->get_post_meta( $parent_id, 'sc_disable_email_restriction', true );
if ( $this->is_wc_gte_30() ) {
$discount_type = $coupon->get_discount_type();
$coupon_code = $coupon->get_code();
} else {
$discount_type = ( ! empty( $coupon->discount_type ) ) ? $coupon->discount_type : '';
$coupon_code = ( ! empty( $coupon->code ) ) ? $coupon->code : '';
}
$coupon_amount = $this->get_amount( $coupon, true, $order );
$coupon_details = array(
$receiver_email => array(
'parent' => $parent_id,
'code' => $coupon_code,
'amount' => $coupon_amount,
),
);
$receiver_name = '';
$message_from_sender = '';
$gift_certificate_sender_name = '';
$gift_certificate_sender_email = '';
$is_gift = ( true === $is_callable_order_get_meta ) ? $order->get_meta( 'is_gift' ) : $this->get_post_meta( $order_id, 'is_gift', true );
// In case of auto generated coupons receiver's details are saved in generated coupon.
if ( 'yes' === $auto_generate ) {
$coupon_receiver_details = ( true === $is_callable_coupon_get_meta ) ? $coupon->get_meta( 'wc_sc_coupon_receiver_details' ) : $this->get_post_meta( $coupon_id, 'wc_sc_coupon_receiver_details', true );
if ( ! empty( $coupon_receiver_details ) && is_array( $coupon_receiver_details ) ) {
$message_from_sender = $coupon_receiver_details['message_from_sender'];
$gift_certificate_sender_name = $coupon_receiver_details['gift_certificate_sender_name'];
$gift_certificate_sender_email = $coupon_receiver_details['gift_certificate_sender_email'];
}
} else {
$receivers_messages = ( true === $is_callable_order_get_meta ) ? $order->get_meta( 'gift_receiver_message' ) : $this->get_post_meta( $order_id, 'gift_receiver_message', true );
if ( strpos( $sender_message_index_key, ':' ) > 0 ) {
$index_keys = explode( ':', $sender_message_index_key );
$coupon_index = $index_keys[0];
$message_index = $index_keys[1];
if ( isset( $receivers_messages[ $coupon_index ][ $message_index ] ) ) {
$message_from_sender = $receivers_messages[ $coupon_index ][ $message_index ];
}
}
}
$this->sa_email_coupon( $coupon_details, $discount_type, $order_id, $receiver_name, $message_from_sender, $gift_certificate_sender_name, $gift_certificate_sender_email, $is_gift );
if ( ( 'no' === $sc_disable_email_restriction || empty( $sc_disable_email_restriction ) ) ) {
$old_customers_email_ids = (array) maybe_unserialize( ( $this->is_callable( $coupon, 'get_email_restrictions' ) ) ? $coupon->get_email_restrictions() : $this->get_post_meta( $coupon_id, 'customer_email', true ) );
$old_customers_email_ids[] = $receiver_email;
if ( true === $is_callable_coupon_update_meta_data ) {
$coupon->set_email_restrictions( $old_customers_email_ids );
} else {
update_post_meta( $coupon_id, 'customer_email', $old_customers_email_ids );
}
}
if ( ! empty( $ref_key ) ) {
$scheduled_actions_ids = ( true === $is_callable_coupon_get_meta ) ? $coupon->get_meta( 'wc_sc_scheduled_actions_ids' ) : $this->get_post_meta( $coupon_id, 'wc_sc_scheduled_actions_ids', true );
if ( isset( $scheduled_actions_ids[ $ref_key ] ) ) {
unset( $scheduled_actions_ids[ $ref_key ] );
}
if ( ! empty( $scheduled_actions_ids ) ) {
if ( true === $is_callable_coupon_update_meta_data ) {
$coupon->update_meta_data( 'wc_sc_scheduled_actions_ids', $scheduled_actions_ids );
} else {
update_post_meta( $coupon_id, 'wc_sc_scheduled_actions_ids', $scheduled_actions_ids );
}
} else {
// Delete scheduled action ids meta since it is empty now.
$this->delete_post_meta( $coupon_id, 'wc_sc_scheduled_actions_ids', null, $coupon );
}
}
if ( $this->is_callable( $coupon, 'save' ) ) {
$coupon->save();
}
}
}
}
/**
* Function to send scheduled coupon's e-mail containing coupon code to receiver. It is triggered through Action Scheduler
*
* @param string $auto_generate is auto generated coupon.
* @param int $coupon_id Associated coupon id.
* @param int $parent_id Associated parent coupon id.
* @param string $receiver_email receiver email.
* @param string $ref_key timestamp based reference key.
*/
public function import_send_scheduled_coupon_email( $auto_generate = '', $coupon_id = 0, $parent_id = 0, $receiver_email = '', $ref_key = '' ) {
if ( ! empty( $coupon_id ) && ! empty( $receiver_email ) ) {
$coupon = new WC_Coupon( $coupon_id );
$coupon_status = ( $this->is_wc_greater_than( '6.1.2' ) && $this->is_callable( $coupon, 'get_status' ) ) ? $coupon->get_status() : get_post_status( $coupon_id );
if ( ! in_array( $coupon_status, array( 'publish', 'future' ), true ) ) {
return;
}
if ( is_a( $coupon, 'WC_Coupon' ) ) {
$is_update_coupon = false;
$is_callable_coupon_get_meta = $this->is_callable( $coupon, 'get_meta' );
$is_callable_coupon_update_meta_data = $this->is_callable( $coupon, 'update_meta_data' );
if ( $this->is_wc_gte_30() ) {
$discount_type = $this->is_callable( $coupon, 'get_discount_type' ) ? $coupon->get_discount_type() : '';
$coupon_code = $this->is_callable( $coupon, 'get_code' ) ? $coupon->get_code() : '';
} else {
$discount_type = ( ! empty( $coupon->discount_type ) ) ? $coupon->discount_type : '';
$coupon_code = ( ! empty( $coupon->code ) ) ? $coupon->code : '';
}
$coupon_amount = $this->get_amount( $coupon, true );
$coupon_details = array(
$receiver_email => array(
'parent' => $parent_id,
'code' => $coupon_code,
'amount' => $coupon_amount,
),
);
$this->sa_email_coupon( $coupon_details, $discount_type, 0 );
if ( ! empty( $ref_key ) ) {
$scheduled_actions_ids = ( true === $is_callable_coupon_get_meta ) ? $coupon->get_meta( 'wc_sc_scheduled_actions_ids' ) : $this->get_post_meta( $coupon_id, 'wc_sc_scheduled_actions_ids', true );
if ( isset( $scheduled_actions_ids[ $ref_key ] ) ) {
unset( $scheduled_actions_ids[ $ref_key ] );
}
if ( ! empty( $scheduled_actions_ids ) ) {
if ( true === $is_callable_coupon_update_meta_data ) {
$coupon->update_meta_data( 'wc_sc_scheduled_actions_ids', $scheduled_actions_ids );
$is_update_coupon = true;
} else {
$this->update_post_meta( $coupon_id, 'wc_sc_scheduled_actions_ids', $scheduled_actions_ids );
}
} else {
// Delete scheduled action ids meta since it is empty now.
$this->delete_post_meta( $coupon_id, 'wc_sc_scheduled_actions_ids', null, $coupon );
}
}
if ( true === $is_update_coupon && $this->is_callable( $coupon, 'save' ) ) {
$coupon->save();
}
}
}
}
/**
* Function to process scheduled coupons.
*
* @param int $coupon_id published coupon's id.
*/
public function process_published_scheduled_coupon( $coupon_id = 0 ) {
$post_type = $this->get_post_type( $coupon_id );
if ( 'shop_coupon' !== $post_type ) {
return false;
}
$coupon = new WC_Coupon( $coupon_id );
if ( is_a( $coupon, 'WC_Coupon' ) ) {
$is_callable_coupon_get_meta = $this->is_callable( $coupon, 'get_meta' );
$order_id = ( true === $is_callable_coupon_get_meta ) ? $coupon->get_meta( 'generated_from_order_id' ) : $this->get_post_meta( $coupon_id, 'generated_from_order_id', true );
$order = wc_get_order( $order_id );
if ( is_a( $order, 'WC_Order' ) ) {
$coupon_receiver_details = ( true === $is_callable_coupon_get_meta ) ? $coupon->get_meta( 'wc_sc_coupon_receiver_details' ) : $this->get_post_meta( $coupon_id, 'wc_sc_coupon_receiver_details', true );
if ( ! empty( $coupon_receiver_details ) && is_array( $coupon_receiver_details ) ) {
$parent_id = $coupon_receiver_details['coupon_details']['parent'];
$receiver_email = $coupon_receiver_details['gift_certificate_receiver_email'];
$gift_certificate_sender_name = $coupon_receiver_details['gift_certificate_sender_name'];
$gift_certificate_sender_email = $coupon_receiver_details['gift_certificate_sender_email'];
$sending_timestamp = get_post_time( 'U', true, $coupon_id ); // Get coupon publish timestamp.
$action_args = array(
'auto_generate' => 'yes',
'coupon_id' => $coupon_id,
'parent_id' => $parent_id, // Parent coupon id.
'order_id' => $order_id,
'receiver_email' => $receiver_email,
'message_index_key' => '',
'ref_key' => uniqid(), // A unique timestamp key to relate action schedulers with their coupons.
);
$is_scheduled = $this->schedule_coupon_email( $action_args, $sending_timestamp );
if ( ! $is_scheduled ) {
if ( $this->is_wc_gte_30() ) {
$coupon_code = $coupon->get_code();
} else {
$coupon_code = ( ! empty( $coupon->code ) ) ? $coupon->code : '';
}
/* translators: 1. Receiver email 2. Coupon code 3. Order id */
$this->log( 'error', sprintf( __( 'Failed to schedule email to "%1$s" for coupon "%2$s" received from order #%3$s.', 'woocommerce-smart-coupons' ), $receiver_email, $coupon_code, $order_id ) );
}
}
}
}
}
/**
* Function to delete action schedulers when associated coupon is deleted.
*
* @param int $coupon_id coupon id.
*/
public function delete_scheduled_coupon_actions( $coupon_id = 0 ) {
global $post_type;
if ( 'shop_coupon' !== $post_type ) {
return false;
}
$coupon = new WC_Coupon( $coupon_id );
if ( is_a( $coupon, 'WC_Coupon' ) ) {
$scheduled_actions_ids = ( $this->is_callable( $coupon, 'get_meta' ) ) ? $coupon->get_meta( 'wc_sc_scheduled_actions_ids' ) : $this->get_post_meta( $coupon_id, 'wc_sc_scheduled_actions_ids', true );
if ( ! empty( $scheduled_actions_ids ) && is_array( $scheduled_actions_ids ) ) {
if ( ! class_exists( 'ActionScheduler' ) || ! is_callable( array( 'ActionScheduler', 'store' ) ) ) {
return false;
}
foreach ( $scheduled_actions_ids as $ref_key => $action_id ) {
$action_scheduler = ActionScheduler::store()->fetch_action( $action_id );
if ( is_a( $action_scheduler, 'ActionScheduler_Action' ) && is_callable( array( $action_scheduler, 'is_finished' ) ) ) {
$is_action_complete = $action_scheduler->is_finished();
// Delete only unfinished actions related to coupon.
if ( ! $is_action_complete ) {
ActionScheduler::store()->delete_action( $action_id );
}
}
}
}
}
}
/**
* Function to check if passed timestamp is valid.
*
* @param string $timestamp timestamp.
* @return boolean is valid timestamp.
*/
public function is_valid_timestamp( $timestamp = '' ) {
if ( empty( $timestamp ) || ! is_numeric( $timestamp ) ) {
return false;
}
// Check if time is already passed.
if ( time() > $timestamp ) {
return false;
}
return true;
}
/**
* Function to enqueue scripts in footer.
*/
public function enqueue_admin_footer_scripts() {
global $pagenow, $typenow;
if ( empty( $pagenow ) || 'edit.php' !== $pagenow ) {
return;
}
$coupon_status = ( ! empty( $_GET['post_status'] ) ) ? wc_clean( wp_unslash( $_GET['post_status'] ) ) : ''; // phpcs:ignore
if ( 'edit.php' === $pagenow && 'shop_coupon' === $typenow && 'trash' === $coupon_status ) {
if ( ! wp_script_is( 'jquery' ) ) {
wp_enqueue_script( 'jquery' );
}
?>
'no',
);
if ( ! empty( $coupon_id ) ) {
$coupon = new WC_Coupon( $coupon_id );
if ( is_a( $coupon, 'WC_Coupon' ) ) {
$scheduled_actions_ids = ( $this->is_callable( $coupon, 'get_meta' ) ) ? $coupon->get_meta( 'wc_sc_scheduled_actions_ids' ) : $this->get_post_meta( $coupon_id, 'wc_sc_scheduled_actions_ids', true );
if ( is_array( $scheduled_actions_ids ) && ! empty( $scheduled_actions_ids ) ) {
$response['has_scheduled_actions'] = 'yes';
}
}
}
wp_send_json( $response );
}
/**
* Register new endpoint to use inside My Account page.
*/
public function sc_add_endpoints() {
if ( empty( WC_SC_Display_Coupons::$endpoint ) ) {
WC_SC_Display_Coupons::$endpoint = WC_SC_Display_Coupons::get_endpoint();
}
if ( $this->is_wc_gte_26() ) {
add_rewrite_endpoint( WC_SC_Display_Coupons::$endpoint, EP_ROOT | EP_PAGES );
$this->sc_check_if_flushed_rules();
}
}
/**
* To register Smart Coupons Endpoint after plugin is activated - Necessary
*/
public function sc_check_if_flushed_rules() {
$sc_check_flushed_rules = get_option( 'sc_flushed_rules', 'notfound' );
if ( 'notfound' === $sc_check_flushed_rules ) {
flush_rewrite_rules(); // phpcs:ignore
update_option( 'sc_flushed_rules', 'found', 'no' );
}
}
/**
* Register & enqueue Smart Coupons CSS
*/
public function register_plugin_styles() {
global $pagenow;
$is_frontend = ( ! is_admin() ) ? true : false;
$is_valid_post_page = ( ! empty( $pagenow ) && in_array( $pagenow, array( 'edit.php', 'post.php', 'post-new.php' ), true ) ) ? true : false;
$is_valid_admin_page = ( ( ! empty( $_GET['page'] ) && 'wc-smart-coupons' === wc_clean( wp_unslash( $_GET['page'] ) ) ) || ( ! empty( $_GET['tab'] ) && 'wc-smart-coupons' === wc_clean( wp_unslash( $_GET['tab'] ) ) ) ) ? true : false; // phpcs:ignore
if ( $is_frontend || $is_valid_admin_page || $is_valid_post_page ) {
$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
wp_register_style( 'smart-coupon', untrailingslashit( plugins_url( '/', WC_SC_PLUGIN_FILE ) ) . '/assets/css/smart-coupon' . $suffix . '.css', array(), $this->plugin_data['Version'] );
wp_register_style( 'smart-coupon-designs', untrailingslashit( plugins_url( '/', WC_SC_PLUGIN_FILE ) ) . '/assets/css/smart-coupon-designs.css', array(), $this->plugin_data['Version'] );
}
}
/**
* Get coupon style attributes
*
* @return string The coupon style attribute
*/
public function get_coupon_style_attributes() {
$styles = array();
$coupon_design = get_option( 'wc_sc_setting_coupon_design', 'basic' );
if ( 'custom-design' !== $coupon_design ) {
$styles = array(
'background-color: var(--sc-color1) !important;',
'color: var(--sc-color2) !important;',
'border-color: var(--sc-color3) !important;',
);
}
$styles = implode( ' ', $styles );
return apply_filters( 'wc_sc_coupon_style_attributes', $styles );
}
/**
* Get coupon container classes
*
* @return string The coupon container classes
*/
public function get_coupon_container_classes() {
return implode( ' ', apply_filters( 'wc_sc_coupon_container_classes', array( 'medium', get_option( 'wc_sc_setting_coupon_design', 'basic' ) ) ) );
}
/**
* Get coupon content classes
*
* @return string The coupon content classes
*/
public function get_coupon_content_classes() {
return implode( ' ', apply_filters( 'wc_sc_coupon_content_classes', array( 'dashed', 'small' ) ) );
}
/**
* Formatted coupon data
*
* @param WC_Coupon $coupon Coupon object.
* @return array $coupon_data Associative array containing formatted coupon data.
*/
public function get_coupon_meta_data( $coupon ) {
global $store_credit_label, $post;
$order = null;
if ( ! empty( $post->ID ) && 'shop_order' === $this->get_post_type( $post->ID ) ) {
$order = wc_get_order( $post->ID );
}
$all_discount_types = wc_get_coupon_types();
if ( $this->is_wc_gte_30() ) {
$coupon_id = ( ! empty( $coupon ) && is_callable( array( $coupon, 'get_id' ) ) ) ? $coupon->get_id() : 0;
$discount_type = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_discount_type' ) ) ) ? $coupon->get_discount_type() : '';
} else {
$coupon_id = ( ! empty( $coupon->id ) ) ? $coupon->id : 0;
$discount_type = ( ! empty( $coupon->discount_type ) ) ? $coupon->discount_type : '';
}
$coupon_amount = $this->get_amount( $coupon, true, $order );
$coupon_data = array();
switch ( $discount_type ) {
case 'smart_coupon':
$coupon_data['coupon_type'] = ! empty( $store_credit_label['singular'] ) ? ucwords( $store_credit_label['singular'] ) : __( 'Store Credit', 'woocommerce-smart-coupons' );
$coupon_data['coupon_amount'] = wc_price( $coupon_amount );
break;
case 'fixed_cart':
$coupon_data['coupon_type'] = __( 'Cart Discount', 'woocommerce-smart-coupons' );
$coupon_data['coupon_amount'] = wc_price( $coupon_amount );
break;
case 'fixed_product':
$coupon_data['coupon_type'] = __( 'Product Discount', 'woocommerce-smart-coupons' );
$coupon_data['coupon_amount'] = wc_price( $coupon_amount );
break;
case 'percent_product':
$coupon_data['coupon_type'] = __( 'Product Discount', 'woocommerce-smart-coupons' );
$coupon_data['coupon_amount'] = $coupon_amount . '%';
break;
case 'percent':
$coupon_data['coupon_type'] = ( $this->is_wc_gte_30() ) ? __( 'Discount', 'woocommerce-smart-coupons' ) : __( 'Cart Discount', 'woocommerce-smart-coupons' );
$coupon_data['coupon_amount'] = $coupon_amount . '%';
$max_discount = $this->get_post_meta( $coupon_id, 'wc_sc_max_discount', true, true, $order );
if ( ! empty( $max_discount ) && is_numeric( $max_discount ) ) {
/* translators: %s: Maximum coupon discount amount */
$coupon_data['coupon_type'] .= ' ' . sprintf( __( ' upto %s', 'woocommerce-smart-coupons' ), wc_price( $max_discount ) );
}
break;
default:
$default_coupon_type = ( ! empty( $all_discount_types[ $discount_type ] ) ) ? $all_discount_types[ $discount_type ] : ucwords( str_replace( array( '_', '-' ), ' ', $discount_type ) );
$coupon_data['coupon_type'] = apply_filters( 'wc_sc_coupon_type', $default_coupon_type, $coupon, $all_discount_types );
$coupon_data['coupon_amount'] = apply_filters( 'wc_sc_coupon_amount', $coupon_amount, $coupon );
break;
}
return $coupon_data;
}
/**
* Generate coupon description
*
* @param array $args The arguments.
* @return string
*/
public function generate_coupon_description( $args = array() ) {
$coupon = ( ! empty( $args['coupon_object'] ) ) ? $args['coupon_object'] : null;
$descriptions = array();
$descriptions_data = array();
if ( $this->is_wc_gte_30() && is_object( $coupon ) ) {
$discount_type = ( is_callable( array( $coupon, 'get_discount_type' ) ) ) ? $coupon->get_discount_type() : '';
$expiry_time = ( is_callable( array( $coupon, 'get_meta' ) ) ) ? $coupon->get_meta( 'wc_sc_expiry_time' ) : '';
$expiry_needed_in_design = array( 'ticket', 'special' );
$design = get_option( 'wc_sc_setting_coupon_design', 'basic' );
$descriptions_data['minimum_amount'] = ( is_callable( array( $coupon, 'get_minimum_amount' ) ) ) ? $coupon->get_minimum_amount() : '';
$descriptions_data['maximum_amount'] = ( is_callable( array( $coupon, 'get_maximum_amount' ) ) ) ? $coupon->get_maximum_amount() : '';
$descriptions_data['exclude_sale_items'] = ( is_callable( array( $coupon, 'get_exclude_sale_items' ) ) ) ? $coupon->get_exclude_sale_items() : '';
$descriptions_data['product_ids'] = ( is_callable( array( $coupon, 'get_product_ids' ) ) ) ? $coupon->get_product_ids() : array();
$descriptions_data['excluded_product_ids'] = ( is_callable( array( $coupon, 'get_excluded_product_ids' ) ) ) ? $coupon->get_excluded_product_ids() : array();
$descriptions_data['product_categories'] = ( is_callable( array( $coupon, 'get_product_categories' ) ) ) ? $coupon->get_product_categories() : array();
$descriptions_data['excluded_product_categories'] = ( is_callable( array( $coupon, 'get_excluded_product_categories' ) ) ) ? $coupon->get_excluded_product_categories() : array();
$check_descriptions_data = array_filter( $descriptions_data );
if ( in_array( $design, $expiry_needed_in_design, true ) || empty( $check_descriptions_data ) ) {
$descriptions_data['date_expires'] = ( is_callable( array( $coupon, 'get_date_expires' ) ) ) ? $coupon->get_date_expires() : '';
}
$max_fields = apply_filters(
'wc_sc_max_fields_to_show_in_coupon_description',
2,
array(
'source' => $this,
'coupon_object' => $coupon,
)
);
if ( ! empty( $descriptions_data ) ) {
foreach ( $descriptions_data as $key => $data ) {
if ( count( $descriptions ) > $max_fields ) {
break;
}
if ( ! empty( $data ) ) {
switch ( $key ) {
case 'minimum_amount':
/* translators: Formatted minimum amount */
$descriptions[] = sprintf( __( 'Spend at least %s', 'woocommerce-smart-coupons' ), wc_price( $data ) );
break;
case 'maximum_amount':
/* translators: Formatted maximum amount */
$descriptions[] = sprintf( __( 'Spend up to %s', 'woocommerce-smart-coupons' ), wc_price( $data ) );
break;
case 'exclude_sale_items':
/* translators: Formatted maximum amount */
$descriptions[] = sprintf( __( 'Not valid for sale items', 'woocommerce-smart-coupons' ), wc_price( $data ) );
break;
case 'product_ids':
$get_product_names = $this->get_coupon_product_names( $data );
$product_names = ( ! empty( $get_product_names ) && is_array( $get_product_names ) ) ? implode( ', ', $get_product_names ) : '';
/* translators: Product names */
$descriptions[] = sprintf( __( 'Valid for %s', 'woocommerce-smart-coupons' ), $product_names );
break;
case 'excluded_product_ids':
$get_product_names = $this->get_coupon_product_names( $data );
$product_names = ( ! empty( $get_product_names ) && is_array( $get_product_names ) ) ? implode( ', ', $get_product_names ) : '';
/* translators: Excluded product names */
$descriptions[] = sprintf( __( 'Not valid for %s', 'woocommerce-smart-coupons' ), $product_names );
break;
case 'product_categories':
$get_product_categories = $this->get_coupon_category_names( $data );
$product_categories = ( ! empty( $get_product_categories ) ) ? implode( ', ', $get_product_categories ) : '';
$count_product_categories = ( ! empty( $get_product_categories ) ) ? count( $get_product_categories ) : 1;
/* translators: 1: The category names */
$descriptions[] = sprintf( esc_html( _n( 'Valid for category %s', 'Valid for categories %s', $count_product_categories, 'woocommerce-smart-coupons' ) ), $product_categories );
break;
case 'excluded_product_categories':
$get_product_categories = $this->get_coupon_category_names( $data );
$product_categories = ( ! empty( $get_product_categories ) ) ? implode( ', ', $get_product_categories ) : '';
$count_product_categories = ( ! empty( $get_product_categories ) ) ? count( $get_product_categories ) : 1;
/* translators: 1: The category names excluded */
$descriptions[] = sprintf( esc_html( _n( 'Not valid for category %s', 'Not valid for categories %s', $count_product_categories, 'woocommerce-smart-coupons' ) ), $product_categories );
break;
case 'date_expires':
if ( $data instanceof WC_DateTime ) {
$expiry_date = ( is_object( $data ) && is_callable( array( $data, 'getTimestamp' ) ) ) ? $data->getTimestamp() : null;
} elseif ( ! is_int( $expiry_date ) ) {
$expiry_date = $this->strtotime( $expiry_date );
}
if ( ! empty( $expiry_date ) && is_int( $expiry_date ) && ! empty( $expiry_time ) ) {
$expiry_date += $expiry_time; // Adding expiry time to expiry date.
}
if ( ! empty( $expiry_date ) ) {
/* translators: 1: The expiry date */
$descriptions[] = sprintf( __( 'Expiry: %s', 'woocommerce-smart-coupons' ), $this->get_expiration_format( $expiry_date ) );
}
break;
}
}
}
}
}
if ( empty( $descriptions ) ) {
$descriptions[] = __( 'Valid on entire range of products. Buy anything in the store.', 'woocommerce-smart-coupons' );
}
return apply_filters(
'wc_sc_generated_coupon_description',
implode( '. ', $descriptions ),
array(
'source' => $this,
'coupon_object' => $coupon,
)
);
}
/**
* Get coupon category names.
*
* @since 5.7.0
*
* @param array $category_ids Category IDs.
* @return array
*/
public function get_coupon_category_names( $category_ids = array() ) {
$category_names = array();
if ( empty( $category_ids ) || ! is_array( $category_ids ) ) {
return $category_names;
}
$category_name_count_restriction = (int) apply_filters(
'wc_sc_max_restricted_category_names',
2,
array(
'source' => $this,
'data' => $category_ids,
)
);
if ( count( $category_ids ) > $category_name_count_restriction ) {
$category_ids = array_slice( $category_ids, 0, $category_name_count_restriction );
}
$category_names = get_terms(
array(
'taxonomy' => 'product_cat',
'include' => $category_ids,
'fields' => 'id=>name',
'get' => 'all',
)
);
return array_filter( $category_names );
}
/**
* Get coupon product's names.
*
* @since 5.7.0
*
* @param array $product_ids Product IDs.
* @return array
*/
public function get_coupon_product_names( $product_ids = array() ) {
$product_names = array();
if ( empty( $product_ids ) || ! is_array( $product_ids ) ) {
return $product_names;
}
$data_count = count( $product_ids );
$product_name_count = 0;
$product_name_count_restriction = (int) apply_filters(
'wc_sc_max_restricted_product_names',
2,
array(
'source' => $this,
'data' => $product_ids,
)
);
for ( $i = 0; $i < $data_count && $product_name_count < $product_name_count_restriction; $i++ ) {
$product = wc_get_product( $product_ids[ $i ] );
if ( is_object( $product ) && is_callable( array( $product, 'get_name' ) ) ) {
$product_names[] = $product->get_name();
$product_name_count++;
}
}
return array_filter( $product_names );
}
/**
* Get valid coupon designs
*
* @return array
*/
public function get_valid_coupon_designs() {
$valid_designs = array(
'flat',
'promotion',
'ticket',
'festive',
'special',
'shipment',
'cutout',
'deliver',
'clipper',
'basic',
'deal',
'custom-design',
);
return $valid_designs;
}
/**
* Get coupon design thumbnail src
*
* @param array $args The arguments.
* @return string
*/
public function get_coupon_design_thumbnail_src( $args = array() ) {
$coupon = ( ! empty( $args['coupon_object'] ) ) ? $args['coupon_object'] : null;
$src = '';
$src_selected = '';
$placeholder = wc_placeholder_img_src();
if ( is_object( $coupon ) ) {
$coupon_product_ids = ( is_callable( array( $coupon, 'get_product_ids' ) ) ) ? $coupon->get_product_ids() : array();
if ( ! empty( $coupon_product_ids ) ) {
$product_id = current( $coupon_product_ids );
$product = wc_get_product( $product_id );
$thumbnail_id = ( is_object( $product ) && is_callable( array( $product, 'get_image_id' ) ) ) ? $product->get_image_id() : '';
} else {
$coupon_product_category_ids = ( is_callable( array( $coupon, 'get_product_categories' ) ) ) ? $coupon->get_product_categories() : array();
if ( ! empty( $coupon_product_category_ids ) ) {
$category_id = current( $coupon_product_category_ids );
$thumbnail_id = get_term_meta( $category_id, 'thumbnail_id', true );
}
}
$src_array = ( ! empty( $thumbnail_id ) ) ? wp_get_attachment_image_src( $thumbnail_id, 'woocommerce_thumbnail' ) : array();
$src = ( ! empty( $src_array[0] ) ) ? $src_array[0] : wc_placeholder_img_src();
if ( ! empty( $src ) && strpos( $src, $placeholder ) !== false ) {
$src = '';
}
}
if ( empty( $src ) ) {
$src_set = array();
if ( $this->is_wc_gte_30() ) {
$discount_type = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_discount_type' ) ) ) ? $coupon->get_discount_type() : '';
$is_free_shipping = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_free_shipping' ) ) ) ? ( ( $coupon->get_free_shipping() ) ? 'yes' : 'no' ) : '';
} else {
$discount_type = ( ! empty( $coupon->discount_type ) ) ? $coupon->discount_type : '';
$is_free_shipping = ( ! empty( $coupon->free_shipping ) ) ? $coupon->free_shipping : '';
}
if ( 'yes' === $is_free_shipping ) {
$src_set = array(
'delivery-motorcyle.svg',
);
} else {
switch ( $discount_type ) {
case 'smart_coupon':
$src_set = array(
'giftbox-color.svg',
);
break;
case 'fixed_cart':
$src_set = array(
'sale-splash-tag.svg',
);
break;
case 'fixed_product':
$src_set = array(
'product-package-box.svg',
);
break;
case 'percent_product':
$src_set = array(
'cart-discount.svg',
);
break;
case 'percent':
$src_set = array(
'cart-discount.svg',
);
break;
default:
$src_set = apply_filters(
'wc_sc_coupon_design_thumbnail_src_set',
array( 'discount-coupon.svg' ),
array(
'source' => $this,
'coupon_object' => $coupon,
)
);
break;
}
}
if ( ! empty( $src_set ) ) {
$src_index = array_rand( $src_set );
$src_selected = $src_set[ $src_index ];
$file = trailingslashit( plugins_url( '/', WC_SC_PLUGIN_FILE ) ) . 'assets/images/' . $src_selected;
$src = apply_filters(
'wc_sc_coupon_design_thumbnail_src',
$file,
array(
'source' => $this,
'selected' => $src_selected,
'coupon_object' => $coupon,
)
);
}
}
if ( empty( $src ) ) {
$design = ( ! empty( $args['design'] ) ) ? $args['design'] : '';
if ( ! empty( $design ) ) {
switch ( $design ) {
case 'special':
$src_selected = 'giftbox-color.svg';
break;
case 'shipment':
$src_selected = 'product-package-box.svg';
break;
case 'cutout':
$src_selected = 'cart-discount.svg';
break;
case 'deliver':
$src_selected = 'delivery-motorcyle.svg';
break;
case 'deal':
$src_selected = 'discount-coupon.svg';
break;
case 'flat':
case 'promotion':
case 'ticket':
case 'festive':
case 'clipper':
case 'basic':
default:
$src_selected = 'discount-coupon.svg';
break;
}
if ( ! empty( $src_selected ) ) {
$file = trailingslashit( plugins_url( '/', WC_SC_PLUGIN_FILE ) ) . 'assets/images/' . $src_selected;
$src = apply_filters(
'wc_sc_coupon_design_thumbnail_src',
$file,
array(
'source' => $this,
'selected' => $src_selected,
'coupon_object' => $coupon,
)
);
} else {
$src = '';
}
}
}
return $src;
}
/**
* Find if the discount type is percent
*
* @param array $args The arguments.
* @return boolean
*/
public function is_percent_coupon( $args = array() ) {
$is_percent = false;
$coupon = ( ! empty( $args['coupon_object'] ) ) ? $args['coupon_object'] : null;
$percent_discount_types = apply_filters(
'wc_sc_percent_discount_types',
array( 'percent_product', 'percent' ),
array(
'source' => $this,
'coupon_object' => $coupon,
)
);
if ( $this->is_wc_gte_30() ) {
$discount_type = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_discount_type' ) ) ) ? $coupon->get_discount_type() : '';
} else {
$discount_type = ( ! empty( $coupon->discount_type ) ) ? $coupon->discount_type : '';
}
if ( in_array( $discount_type, $percent_discount_types, true ) ) {
$is_percent = true;
}
return $is_percent;
}
/**
* Generate storewide offer coupon description
*
* @param array $args Arguments.
* @return string
*/
public function generate_storewide_offer_coupon_description( $args = array() ) {
$coupon = ( ! empty( $args['coupon_object'] ) ) ? $args['coupon_object'] : false;
$coupon_amount = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_amount' ) ) ) ? $coupon->get_amount( 'edit' ) : 0;
$coupon_code = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_code' ) ) ) ? $coupon->get_code() : '';
if ( empty( $coupon_amount ) || empty( $coupon_code ) ) {
return '';
}
$description = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_description' ) ) ) ? $coupon->get_description() : '';
if ( empty( $description ) ) {
$is_percent = $this->is_percent_coupon( array( 'coupon_object' => $coupon ) );
$currency_symbol = get_woocommerce_currency_symbol();
$before_heading = array(
__( 'Great News!', 'woocommerce-smart-coupons' ),
__( 'Super Savings!', 'woocommerce-smart-coupons' ),
__( 'Ending Soon!', 'woocommerce-smart-coupons' ),
__( 'Limited Time Offer!', 'woocommerce-smart-coupons' ),
__( 'This Week Only!', 'woocommerce-smart-coupons' ),
__( 'Attention!', 'woocommerce-smart-coupons' ),
__( 'You don\'t want to miss this...', 'woocommerce-smart-coupons' ),
__( 'This will be over soon! Hurry.', 'woocommerce-smart-coupons' ),
__( 'Act before the offer expires.', 'woocommerce-smart-coupons' ),
__( 'Don't Miss Out.', 'woocommerce-smart-coupons' ),
);
$heading = array(
/* translators: 1. The discount text */
__( '%s discount on anything you want.', 'woocommerce-smart-coupons' ),
/* translators: 1. The discount text */
__( '%s discount on entire store.', 'woocommerce-smart-coupons' ),
/* translators: 1. The discount text */
__( 'Pick any item today for %s off.', 'woocommerce-smart-coupons' ),
/* translators: 1. The discount text */
__( 'Buy as much as you want. Flat %s off everything.', 'woocommerce-smart-coupons' ),
/* translators: 1. The discount text */
__( 'Flat %s discount on everything today.', 'woocommerce-smart-coupons' ),
);
$before_heading_index = array_rand( $before_heading );
$heading_index = array_rand( $heading );
if ( true === $is_percent ) {
$discount_text = $coupon_amount . '%';
} else {
$discount_text = $currency_symbol . $coupon_amount;
}
$description = sprintf( '%s ' . $heading[ $heading_index ] . ' %s: %s', $before_heading[ $before_heading_index ], '' . $discount_text . '', __( 'Use code', 'woocommerce-smart-coupons' ), '' . $coupon_code . '' );
$description = apply_filters(
'wc_sc_storewide_offer_coupon_description',
$description,
array_merge(
$args,
array(
'before_heading' => $before_heading[ $before_heading_index ],
'heading' => $heading,
'discount_text' => $discount_text,
)
)
);
} else {
/* translators: 1. The coupon code */
$description .= ' ' . sprintf( __( 'Use code: %s', 'woocommerce-smart-coupons' ), '' . $coupon_code . '' );
}
return $description;
}
/**
* Update coupon's email id with the updation of customer profile
*
* @param int $user_id User ID of the user being saved.
*/
public function my_profile_update( $user_id ) {
global $wpdb;
if ( current_user_can( 'edit_user', $user_id ) ) {
$current_user = get_userdata( $user_id );
$old_customers_email_id = $current_user->data->user_email;
$post_email = ( isset( $_POST['email'] ) ) ? wc_clean( wp_unslash( $_POST['email'] ) ) : ''; // phpcs:ignore
if ( ! empty( $post_email ) && $post_email !== $old_customers_email_id ) {
$result = wp_cache_get( 'wc_sc_customers_coupon_ids_' . sanitize_key( $old_customers_email_id ), 'woocommerce_smart_coupons' );
if ( false === $result ) {
$result = $wpdb->get_col( // phpcs:ignore
$wpdb->prepare(
"SELECT post_id
FROM $wpdb->postmeta
WHERE meta_key = %s
AND meta_value LIKE %s
AND post_id IN ( SELECT ID
FROM $wpdb->posts
WHERE post_type = %s)",
'customer_email',
'%' . $wpdb->esc_like( '"' . $old_customers_email_id . '"' ) . '%',
'shop_coupon'
)
);
wp_cache_set( 'wc_sc_customers_coupon_ids_' . sanitize_key( $old_customers_email_id ), $result, 'woocommerce_smart_coupons' );
$this->maybe_add_cache_key( 'wc_sc_customers_coupon_ids_' . sanitize_key( $old_customers_email_id ) );
}
if ( ! empty( $result ) ) {
foreach ( $result as $post_id ) {
$coupon_meta = $this->get_post_meta( $post_id, 'customer_email', true );
$is_update_coupon_meta = false;
if ( ! empty( $coupon_meta ) ) {
foreach ( $coupon_meta as $key => $email_id ) {
if ( $email_id === $old_customers_email_id ) {
$coupon_meta[ $key ] = $post_email;
$is_update_coupon_meta = true;
}
}
}
if ( true === $is_update_coupon_meta ) {
$this->update_post_meta( $post_id, 'customer_email', $coupon_meta );
}
} //end foreach
}
}
}
}
/**
* Method to check whether 'pick_price_from_product' is set or not
*
* @param array $coupons Array of coupon codes.
* @return boolean
*/
public function is_coupon_amount_pick_from_product_price( $coupons ) {
if ( empty( $coupons ) ) {
return false;
}
if ( ! is_array( $coupons ) && is_scalar( $coupons ) ) {
$coupons = array( $coupons );
}
foreach ( $coupons as $coupon_code ) {
$coupon = new WC_Coupon( $coupon_code );
if ( $this->is_wc_gte_30() ) {
if ( ! is_object( $coupon ) || ! is_callable( array( $coupon, 'get_id' ) ) ) {
continue;
}
$coupon_id = $coupon->get_id();
if ( empty( $coupon_id ) ) {
continue;
}
$discount_type = $coupon->get_discount_type();
$is_pick_price_of_product = ( $this->is_callable( $coupon, 'get_meta' ) ) ? $coupon->get_meta( 'is_pick_price_of_product' ) : $this->get_post_meta( $coupon_id, 'is_pick_price_of_product', true );
} else {
$coupon_id = ( ! empty( $coupon->id ) ) ? $coupon->id : 0;
$discount_type = ( ! empty( $coupon->discount_type ) ) ? $coupon->discount_type : '';
$is_pick_price_of_product = get_post_meta( $coupon_id, 'is_pick_price_of_product', true );
}
if ( 'smart_coupon' === $discount_type && 'yes' === $is_pick_price_of_product ) {
return true;
}
}
return false;
}
/**
* Function to find if order is discounted with store credit
*
* @param WC_Order $order Order object.
* @return boolean
*/
public function is_order_contains_store_credit( $order = null ) {
if ( empty( $order ) ) {
return false;
}
$coupons = $order->get_items( 'coupon' );
foreach ( $coupons as $item_id => $item ) {
$code = ( is_object( $item ) && is_callable( array( $item, 'get_name' ) ) ) ? $item->get_name() : trim( $item['name'] );
$coupon = new WC_Coupon( $code );
if ( $this->is_wc_gte_30() ) {
$discount_type = $coupon->get_discount_type();
} else {
$discount_type = ( ! empty( $coupon->discount_type ) ) ? $coupon->discount_type : '';
}
if ( 'smart_coupon' === $discount_type ) {
return true;
}
}
return false;
}
/**
* Function to validate smart coupon for product
*
* @param bool $valid Coupon validity.
* @param WC_Product|null $product Product object.
* @param WC_Coupon|null $coupon Coupon object.
* @param array|null $values Values.
* @return bool $valid
*/
public function smart_coupons_is_valid_for_product( $valid, $product = null, $coupon = null, $values = null ) {
if ( empty( $product ) || empty( $coupon ) ) {
return $valid;
}
if ( $this->is_wc_gte_30() ) {
$product_id = ( is_object( $product ) && is_callable( array( $product, 'get_id' ) ) ) ? $product->get_id() : 0;
$product_parent_id = ( is_object( $product ) && is_callable( array( $product, 'get_parent_id' ) ) ) ? $product->get_parent_id() : 0;
$product_variation_id = ( is_object( $product ) && is_callable( array( $product, 'get_id' ) ) ) ? $product->get_id() : 0;
$discount_type = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_discount_type' ) ) ) ? $coupon->get_discount_type() : '';
$coupon_product_ids = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_product_ids' ) ) ) ? $coupon->get_product_ids() : '';
$coupon_product_categories = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_product_categories' ) ) ) ? $coupon->get_product_categories() : '';
$coupon_excluded_product_ids = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_excluded_product_ids' ) ) ) ? $coupon->get_excluded_product_ids() : '';
$coupon_excluded_product_categories = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_excluded_product_categories' ) ) ) ? $coupon->get_excluded_product_categories() : '';
$is_exclude_sale_items = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_exclude_sale_items' ) ) ) ? ( ( $coupon->get_exclude_sale_items() ) ? 'yes' : 'no' ) : '';
} else {
$product_id = ( ! empty( $product->id ) ) ? $product->id : 0;
$product_parent_id = ( ! empty( $product ) && is_callable( array( $product, 'get_parent' ) ) ) ? $product->get_parent() : 0;
$product_variation_id = ( ! empty( $product->variation_id ) ) ? $product->variation_id : 0;
$discount_type = ( ! empty( $coupon->discount_type ) ) ? $coupon->discount_type : '';
$coupon_product_ids = ( ! empty( $coupon->product_ids ) ) ? $coupon->product_ids : array();
$coupon_product_categories = ( ! empty( $coupon->product_categories ) ) ? $coupon->product_categories : array();
$coupon_excluded_product_ids = ( ! empty( $coupon->exclude_product_ids ) ) ? $coupon->exclude_product_ids : array();
$coupon_excluded_product_categories = ( ! empty( $coupon->exclude_product_categories ) ) ? $coupon->exclude_product_categories : array();
$is_exclude_sale_items = ( ! empty( $coupon->exclude_sale_items ) ) ? $coupon->exclude_sale_items : '';
}
if ( 'smart_coupon' === $discount_type ) {
$product_cats = wc_get_product_cat_ids( $product_id );
// Specific products get the discount.
if ( count( $coupon_product_ids ) > 0 ) {
if ( in_array( $product_id, $coupon_product_ids, true ) || ( isset( $product_variation_id ) && in_array( $product_variation_id, $coupon_product_ids, true ) ) || in_array( $product_parent_id, $coupon_product_ids, true ) ) {
$valid = true;
}
// Category discounts.
} elseif ( count( $coupon_product_categories ) > 0 ) {
if ( count( array_intersect( $product_cats, $coupon_product_categories ) ) > 0 ) {
$valid = true;
}
} else {
// No product ids - all items discounted.
$valid = true;
}
// Specific product ID's excluded from the discount.
if ( count( $coupon_excluded_product_ids ) > 0 ) {
if ( in_array( $product_id, $coupon_excluded_product_ids, true ) || ( isset( $product_variation_id ) && in_array( $product_variation_id, $coupon_excluded_product_ids, true ) ) || in_array( $product_parent_id, $coupon_excluded_product_ids, true ) ) {
$valid = false;
}
}
// Specific categories excluded from the discount.
if ( count( $coupon_excluded_product_categories ) > 0 ) {
if ( count( array_intersect( $product_cats, $coupon_excluded_product_categories ) ) > 0 ) {
$valid = false;
}
}
// Sale Items excluded from discount.
if ( 'yes' === $is_exclude_sale_items ) {
$product_ids_on_sale = wc_get_product_ids_on_sale();
if ( in_array( $product_id, $product_ids_on_sale, true ) || ( isset( $product_variation_id ) && in_array( $product_variation_id, $product_ids_on_sale, true ) ) || in_array( $product_parent_id, $product_ids_on_sale, true ) ) {
$valid = false;
}
}
}
return $valid;
}
/**
* Validate expiry time
*
* @param boolean $expired Whether the coupon is expired or not.
* @param WC_Coupon $coupon The coupon object.
* @param WC_Discounts $discounts The discount object.
* @return boolean
*/
public function validate_expiry_time( $expired = false, $coupon = null, $discounts = null ) {
if ( ! $this->is_wc_gte_30() ) {
return $expired; // Expiry time feature is not supported for lower version of WooCommerce.
}
$expiry_time = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_meta' ) ) ) ? (int) $coupon->get_meta( 'wc_sc_expiry_time' ) : 0;
if ( ! empty( $expiry_time ) ) {
$expiry_date = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_date_expires' ) ) ) ? $coupon->get_date_expires() : '';
if ( ! empty( $expiry_date ) ) {
if ( $expiry_date instanceof WC_DateTime ) {
$expiry_date = ( is_callable( array( $expiry_date, 'getTimestamp' ) ) ) ? $expiry_date->getTimestamp() : null;
} elseif ( ! is_int( $expiry_date ) ) {
$expiry_date = $this->strtotime( $expiry_date );
}
if ( is_int( $expiry_date ) ) {
$expiry_date += $expiry_time; // Adding expiry time to expiry date.
if ( time() <= $expiry_date ) {
$expired = false;
} else {
$expired = true;
}
}
}
}
return $expired;
}
/**
* Wrapper function for strtotime
*
* @param string $date_time The date time.
* @return int
*/
public function strtotime( $date_time = '' ) {
$parsed_date = ( is_string( $date_time ) ) ? date_parse( $date_time ) : array( 'warning_count' => 1 );
if ( ! empty( $parsed_date['warning_count'] ) ) {
return 0;
}
return strtotime( $date_time );
}
/**
* Function to keep valid coupons when individual use coupon is applied
*
* @param array $coupons_to_keep Coupons to keep.
* @param WC_Coupon|boolean $the_coupon Coupon object.
* @param array $applied_coupons Array of applied coupons.
* @return array $coupons_to_keep
*/
public function smart_coupons_override_individual_use( $coupons_to_keep = array(), $the_coupon = false, $applied_coupons = array() ) {
if ( $this->is_wc_gte_30() ) {
foreach ( $applied_coupons as $code ) {
$coupon = new WC_Coupon( $code );
if ( 'smart_coupon' === $coupon->get_discount_type() && ! $coupon->get_individual_use() && ! in_array( $code, $coupons_to_keep, true ) ) {
$coupons_to_keep[] = $code;
}
}
}
return $coupons_to_keep;
}
/**
* Force apply store credit even if the individual coupon already exists in cart
*
* @param boolean $is_apply Apply with individual use coupon.
* @param WC_Coupon|boolean $the_coupon Coupon object.
* @param WC_Coupon|boolean $applied_coupon Coupon object.
* @param array $applied_coupons Array of applied coupons.
* @return boolean
*/
public function smart_coupons_override_with_individual_use( $is_apply = false, $the_coupon = false, $applied_coupon = false, $applied_coupons = array() ) {
if ( $this->is_wc_gte_30() ) {
if ( ! $is_apply && 'smart_coupon' === $the_coupon->get_discount_type() && ! $the_coupon->get_individual_use() ) {
$is_apply = true;
}
}
return $is_apply;
}
/**
* Function to add appropriate discount total filter
*/
public function smart_coupons_discount_total_filters() {
if ( WCS_SC_Compatibility::is_cart_contains_subscription() && WCS_SC_Compatibility::is_wcs_gte( '2.0.0' ) ) {
add_action( 'woocommerce_after_calculate_totals', array( $this, 'smart_coupons_after_calculate_totals' ), 9999 );
} else {
add_action( 'woocommerce_after_calculate_totals', array( $this, 'smart_coupons_after_calculate_totals' ), 9999 );
global $current_screen;
if ( ! empty( $current_screen ) && 'edit-shop_order' !== $current_screen ) {
add_filter( 'woocommerce_order_get_total', array( $this, 'smart_coupons_order_discounted_total' ), 10, 2 );
}
}
}
/**
* Function to handle store credit application
*/
public function sc_handle_store_credit_application() {
$apply_before_tax = get_option( 'woocommerce_smart_coupon_apply_before_tax', 'no' );
if ( $this->is_wc_gte_30() && 'yes' === $apply_before_tax ) {
include_once 'class-wc-sc-apply-before-tax.php';
} else {
add_action( 'wp_loaded', array( $this, 'smart_coupons_discount_total_filters' ), 20 );
add_action( 'woocommerce_order_after_calculate_totals', array( $this, 'order_calculate_discount_amount' ), 10, 2 );
add_action( 'woocommerce_order_after_calculate_totals', array( $this, 'order_calculate_discount_amount_rest_api' ), 10, 2 );
add_filter( 'woocommerce_cart_totals_coupon_html', array( $this, 'cart_totals_coupon_html' ), 99, 3 );
}
}
/**
* Function calculate actual order total without discount
*
* @param WC_Order $order Order object.
* @return float $order_total
*/
public function get_original_order_total_before_discount( $order = null ) {
$order_total = 0;
if ( ! is_object( $order ) || ! $order instanceof WC_Order ) {
return $order_total;
}
$line_items = $order->get_items( 'line_item' );
$fee_items = $order->get_items( 'fee' );
if ( is_array( $line_items ) && ! empty( $line_items ) ) {
foreach ( $line_items as $order_item ) {
if ( ! $order_item instanceof WC_Order_Item_Product ) {
continue;
}
$order_total += $order->get_line_subtotal( $order_item, true );
}
}
if ( $this->is_callable( $order, 'get_shipping_total' ) && $this->is_callable( $order, 'get_shipping_tax' ) ) {
$order_total += ( (float) $order->get_shipping_total() + (float) $order->get_shipping_tax() );
}
if ( is_array( $fee_items ) && ! empty( $fee_items ) ) {
foreach ( $fee_items as $fee_item ) {
if ( ! $fee_item instanceof WC_Order_Item_Fee ) {
continue;
}
$order_total += $order->get_item_total( $fee_item, true );
}
}
return $order_total;
}
/**
* Function to update smart coupon balance that are created manually. This method will call apply before tax enable/disable.
*
* @param bool $and_taxes Calc taxes if true.
* @param WC_Order $order Order object.
*/
public function update_smart_coupon_order_create_via_admin( $and_taxes = false, $order = null ) {
if ( ! is_object( $order ) || ! $order instanceof WC_Order ) {
return;
}
if ( isset( $order->sc_total_credit_used ) && is_array( $order->sc_total_credit_used ) && count( $order->sc_total_credit_used ) > 0 ) {
// phpcs:disable WordPress.Security.NonceVerification.Missing
$post_action = ! empty( $_POST['action'] ) ? sanitize_text_field( wp_unslash( $_POST['action'] ) ) : '';
// Note*: Deduct Smart Coupon when publish a new order.
if ( in_array( $post_action, array( 'edit_order', 'editpost' ), true ) ) {
$status_exceptions = array( 'auto-draft', 'trash' );
$new_status = '';
$post_status = ! empty( $_POST['post_status'] ) ? sanitize_text_field( wp_unslash( $_POST['post_status'] ) ) : '';
if ( ! empty( $_POST['order_status'] ) ) {
$order_status = sanitize_text_field( wp_unslash( $_POST['order_status'] ?? '' ) );
$new_status = 'wc-' === substr( $order_status, 0, 3 ) ? substr( $order_status, 3 ) : $order_status;
}
if ( 'auto-' === substr( $post_status, 0, 5 ) ) {
$post_status = substr( $post_status, 5 );
}
if ( in_array( 'auto-' === substr( $order->get_status(), 0, 5 ) ? substr( $order->get_status(), 5 ) : $order->get_status(), array( 'draft' ), true ) && in_array( 'auto-' === substr( $post_status, 0, 5 ) ? substr( $post_status, 5 ) : $post_status, array( 'draft' ), true ) && in_array( 'wc-' . $new_status, array_keys( wc_get_order_statuses() ), true ) && ! in_array( $new_status, $status_exceptions, true ) && did_action( 'sc_after_order_calculate_discount_amount' ) <= 0 ) {
do_action( 'sc_after_order_calculate_discount_amount', $order->get_id() );
}
}
$pending_statuses = $this->get_pending_statuses();
$current_applied_code = ( ! empty( $_POST['coupon'] ) ) ? strtolower( wc_clean( wp_unslash( $_POST['coupon'] ) ) ) : ''; // phpcs:ignore
if ( 'woocommerce_add_coupon_discount' === $post_action && $order->has_status( $pending_statuses ) && !empty( $order->get_coupon_codes() ) && in_array( $current_applied_code , array_map( 'strtolower', $order->get_coupon_codes() ) ) && did_action( 'sc_after_order_calculate_discount_amount' ) <= 0 ) { // phpcs:ignore
do_action( 'sc_after_order_calculate_discount_amount', $order->get_id() );
}
// phpcs:enable
}
}
/**
* Function to set store credit amount for orders that are manually created and updated from backend
*
* @param bool $and_taxes Calc taxes if true.
* @param WC_Order $order Order object.
*/
public function order_calculate_discount_amount( $and_taxes = false, $order = null ) {
if ( ! is_object( $order ) || ! $order instanceof WC_Order ) {
return;
}
$order_actions = array( 'woocommerce_add_coupon_discount', 'woocommerce_calc_line_taxes', 'woocommerce_save_order_items', 'woocommerce_remove_order_coupon' );
$order_id = ( $this->is_callable( $order, 'get_id' ) ) ? $order->get_id() : 0;
$post_action = ( ! empty( $_POST['action'] ) ) ? wc_clean( wp_unslash( $_POST['action'] ) ) : ''; // phpcs:ignore
$post_post_type = ( $this->is_hpos() ) ? $this->get_post_type( $order_id ) : ( ( ! empty( $_POST['post_type'] ) ) ? wc_clean( wp_unslash( $_POST['post_type'] ) ) : '' ); // phpcs:ignore
$order_created_via_admin = ! empty( $post_action ) && ( in_array( $post_action, $order_actions, true ) ) || 'admin' === $order->get_created_via() ? true : false;
$discount_total = 0;
$discount_tax = 0;
if ( ( ! empty( $post_action ) && ( in_array( $post_action, $order_actions, true ) || ( ! empty( $post_post_type ) && 'shop_order' === $post_post_type && in_array( $post_action, array( 'edit_order', 'editpost' ), true ) ) ) ) ) {
if ( ! is_callable( array( $order, 'get_id' ) ) ) {
return;
}
if ( empty( $order_id ) ) {
return;
}
$coupons = $order->get_items( 'coupon' );
$total = $this->get_original_order_total_before_discount( $order );
if ( ! empty( $coupons ) ) {
foreach ( $coupons as $item_id => $item ) {
$coupon_code = ( is_object( $item ) && is_callable( array( $item, 'get_name' ) ) ) ? $item->get_name() : trim( $item['name'] );
if ( empty( $coupon_code ) ) {
continue;
}
$coupon = new WC_Coupon( $coupon_code );
$discount_type = $coupon->get_discount_type();
$discount_amount = ( is_object( $item ) && is_callable( array( $item, 'get_discount' ) ) ) ? $item->get_discount() : $this->get_order_item_meta( $item_id, 'discount_amount', true, true );
$discount_amount_tax = ( is_object( $item ) && is_callable( array( $item, 'get_discount_tax' ) ) ) ? $item->get_discount_tax() : $this->get_order_item_meta( $item_id, 'discount_tax', true, true );
if ( 'smart_coupon' === $discount_type ) {
$smart_coupons_contribution = $this->get_post_meta( $order_id, 'smart_coupons_contribution', true, true );
$smart_coupons_contribution = ! empty( $smart_coupons_contribution ) ? $smart_coupons_contribution : array();
if ( ! empty( $smart_coupons_contribution ) && count( $smart_coupons_contribution ) > 0 && array_key_exists( $coupon_code, $smart_coupons_contribution ) ) {
$discount = $smart_coupons_contribution[ $coupon_code ];
if ( $order_created_via_admin ) {
$discount_amount = $discount;
}
} else {
$discount_data = $this->sc_order_get_discount_amount( $total, $coupon, $order );
$discount_amount = isset( $discount_data['discount_total'] ) ? $discount_data['discount_total'] : 0;
$discount_amount_tax = isset( $discount_data['discount_tax'] ) ? $discount_data['discount_tax'] : 0;
$discount = $discount_amount + $discount_amount_tax;
$smart_coupons_contribution[ $coupon_code ] = $discount;
// check if store credit discount does not cross max discount. It is only applicable for manual order creation.
if ( $order_created_via_admin && count( $smart_coupons_contribution ) > 0 && (float) array_sum( $smart_coupons_contribution ) > (float) $order->get_total() ) {
$ignore_discount_amount = (float) array_sum( $smart_coupons_contribution ) - (float) $order->get_total();
$discount -= $ignore_discount_amount;
if ( $discount < 1 ) {
$discount_amount = 0;
$discount_amount_tax = 0;
$discount = 0;
} else {
$discount_amount = $discount;
}
$smart_coupons_contribution[ $coupon_code ] = $discount;
}
$this->update_post_meta( $order_id, 'smart_coupons_contribution', $smart_coupons_contribution, true, $order );
}
if ( is_object( $item ) && is_callable( array( $item, 'set_discount' ) ) && isset( $discount_amount ) ) {
$item->set_discount( $discount_amount );
}
if ( is_object( $item ) && is_callable( array( $item, 'set_discount_tax' ) ) && isset( $discount_amount_tax ) ) {
$item->set_discount_tax( $discount_amount_tax );
}
}
$discount_total += $discount_amount;
$discount_tax += $discount_amount_tax;
}
$order->sc_total_credit_used = isset( $smart_coupons_contribution ) ? $smart_coupons_contribution : array();
$order->set_discount_total( $discount_total );
$order->set_discount_tax( $discount_tax );
$order->set_total( $total - ( $discount_total + $discount_tax ) );
}
}
}
/**
* Function to set store credit amount for orders that are manually created and updated from REST API
*
* @param bool $and_taxes Calc taxes if true.
* @param WC_Order $order Order object.
*/
public function order_calculate_discount_amount_rest_api( $and_taxes, $order = null ) {
if ( ! is_object( $order ) || ! $order instanceof WC_Order ) {
return;
}
$is_rest_api_request = WC()->is_rest_api_request();
$order_id = ( $this->is_callable( $order, 'get_id' ) ) ? $order->get_id() : 0;
$post_post_type = $this->get_post_type( $order_id ); // phpcs:ignore
if ( 'shop_order' === $post_post_type && ( $is_rest_api_request ) ) {
if ( ! is_callable( array( $order, 'get_id' ) ) ) {
return;
}
if ( empty( $order_id ) ) {
return;
}
$coupons = $order->get_items( 'coupon' );
$woocommerce_discount_total = $order->get_total_discount( false );
$actual_discount_total = 0;
$order_discount_total = 0;
$order_discount_tax = 0;
$cart_tax = (float) $order->get_cart_tax();
$cart_discount_tax = (float) $order->get_discount_tax();
if ( ( empty( $cart_tax ) || $cart_tax < 1 ) && $cart_discount_tax > 0 ) { // when coupon fully cover order subtotal.
$cart_tax = $cart_discount_tax;
} elseif ( $cart_discount_tax > 0 && $cart_tax > 0 ) { // when coupon not fully cover order subtotal.
$cart_tax += $cart_discount_tax;
}
$smart_coupons_contribution = $this->get_post_meta( $order_id, 'smart_coupons_contribution', true, true );
$smart_coupons_contribution = ! empty( $smart_coupons_contribution ) ? $smart_coupons_contribution : array();
if ( ! empty( $coupons ) ) {
foreach ( $coupons as $item_id => $item ) {
$coupon_code = ( is_object( $item ) && is_callable( array( $item, 'get_name' ) ) ) ? $item->get_name() : trim( $item['name'] );
if ( empty( $coupon_code ) ) {
continue;
}
$coupon = new WC_Coupon( $coupon_code );
$discount_type = $coupon->get_discount_type();
$discount_amount = ( is_object( $item ) && is_callable( array( $item, 'get_discount' ) ) ) ? $item->get_discount() : $this->get_order_item_meta( $item_id, 'discount_amount', true, true );
$discount_amount_tax = ( is_object( $item ) && is_callable( array( $item, 'get_discount_tax' ) ) ) ? $item->get_discount_tax() : $this->get_order_item_meta( $item_id, 'discount_amount_tax', true, true );
$discount_of_individual_coupon = (float) $discount_amount + (float) $discount_amount_tax;
$actual_discount_total += $discount_of_individual_coupon;
$order_discount_total += $discount_amount;
$order_discount_tax += $discount_amount_tax;
if ( ! $coupon->is_type( array( 'smart_coupon' ) ) && ( $cart_tax >= $discount_amount_tax ) ) {
$cart_tax -= $discount_amount_tax;
}
if ( 'smart_coupon' === $discount_type && empty( $smart_coupons_contribution ) && ! array_key_exists( $coupon_code, $smart_coupons_contribution ) ) {
$smart_coupons_contribution[ $coupon_code ] = $discount_of_individual_coupon;
$this->update_post_meta( $order_id, 'smart_coupons_contribution', $smart_coupons_contribution, true, $order );
}
}
$woocomerce_order_total = (float) $order->get_total();
$diff_discount = 0;
if ( $actual_discount_total > $woocommerce_discount_total ) {
$diff_discount = (float) $actual_discount_total - (float) $woocommerce_discount_total;
} elseif ( $woocommerce_discount_total > $actual_discount_total ) {
$woocomerce_order_total += $woocommerce_discount_total - $actual_discount_total;
}
$order->set_cart_tax( $cart_tax );
$order->set_discount_total( $order_discount_total );
$order->set_discount_tax( $order_discount_tax );
$order->set_total( $woocomerce_order_total - $diff_discount );
}
}
}
/**
* Function to get discount amount for orders
*
* @param float $total Order total.
* @param WC_Coupon $coupon Coupon object.
* @param WC_Order $order Order object.
* @return array $discount_total and $discount_tax
*/
public function sc_order_get_discount_amount( $total = 0, $coupon = null, $order = null ) {
if ( is_a( $coupon, 'WC_Coupon' ) && is_a( $order, 'WC_Order' ) ) {
$discount_line_totals = 0;
$discount_line_taxes = 0;
$discount_type = $coupon->get_discount_type();
$coupon_product_ids = $coupon->get_product_ids();
$coupon_product_categories = $coupon->get_product_categories();
$order_items = $order->get_items( 'line_item' );
$shipping_items = $order->get_items( 'shipping' );
$fee_items = $order->get_items( 'fee' );
if ( 'smart_coupon' === $discount_type ) {
$coupon_amount = $this->get_amount( $coupon, true, $order );
$calculated_total = $total;
if ( count( $coupon_product_ids ) > 0 || count( $coupon_product_categories ) > 0 ) {
$discount = 0;
$discounted_products = array();
foreach ( $order_items as $order_item_id => $order_item ) {
if ( $discount >= $coupon_amount ) {
break;
}
$product_id = ( is_object( $order_item ) && is_callable( array( $order_item, 'get_product_id' ) ) ) ? $order_item->get_product_id() : $order_item['product_id'];
$variation_id = ( is_object( $order_item ) && is_callable( array( $order_item, 'get_variation_id' ) ) ) ? $order_item->get_variation_id() : $order_item['variation_id'];
$line_total = ( is_object( $order_item ) && is_callable( array( $order_item, 'get_total' ) ) ) ? $order_item->get_total() : $order_item['line_total'];
$line_tax = ( is_object( $order_item ) && is_callable( array( $order_item, 'get_total_tax' ) ) ) ? $order_item->get_total_tax() : $order_item['line_tax'];
$product_cats = wc_get_product_cat_ids( $product_id );
if ( count( $coupon_product_categories ) > 0 ) {
$continue = false;
if ( ! empty( $order_item_id ) && ! empty( $discounted_products ) && is_array( $discounted_products ) && in_array( $order_item_id, $discounted_products, true ) ) {
$continue = true;
}
if ( ! $continue && count( array_intersect( $product_cats, $coupon_product_categories ) ) > 0 ) {
$discounted_products[] = ( ! empty( $order_item_id ) ) ? $order_item_id : '';
$discount_line_totals += $line_total;
$discount_line_taxes += $line_tax;
}
}
if ( count( $coupon_product_ids ) > 0 ) {
$continue = false;
if ( ! empty( $order_item_id ) && ! empty( $discounted_products ) && is_array( $discounted_products ) && in_array( $order_item_id, $discounted_products, true ) ) {
$continue = true;
}
if ( ! $continue && in_array( $product_id, $coupon_product_ids, true ) || in_array( $variation_id, $coupon_product_ids, true ) ) {
$discounted_products[] = ( ! empty( $order_item_id ) ) ? $order_item_id : '';
$discount_line_totals += $line_total;
$discount_line_taxes += $line_tax;
}
}
}
$calculated_total = round( ( $discount_line_totals + $discount_line_taxes ), wc_get_price_decimals() );
} else {
if ( ! empty( $order_items ) && is_array( $order_items ) && $coupon_amount > 0 ) {
foreach ( $order_items as $order_item ) {
if ( ! $order_item instanceof WC_Order_Item_Product ) {
continue;
}
if ( $coupon_amount <= 0 ) {
break;
}
$line_total = (float) ( is_object( $order_item ) && is_callable( array( $order_item, 'get_subtotal' ) ) ) ? $order_item->get_subtotal() : $order_item['subtotal'];
$discount_line_total = min( $coupon_amount, $line_total );
$discount_line_totals += $discount_line_total;
$coupon_amount -= $discount_line_total;
if ( ! $discount_line_total > $line_total ) {
$order_item->set_total( $line_total - $discount_line_total );
}
}
foreach ( $order_items as $order_item ) {
if ( ! $order_item instanceof WC_Order_Item_Product ) {
continue;
}
if ( $coupon_amount <= 0 ) {
break;
}
$line_tax = (float) ( is_object( $order_item ) && is_callable( array( $order_item, 'get_subtotal_tax' ) ) ) ? $order_item->get_subtotal_tax() : $order_item['subtotal_tax'];
$discount_line_tax = min( $coupon_amount, $line_tax );
$discount_line_taxes += $discount_line_tax;
$coupon_amount -= $discount_line_tax;
if ( ! $discount_line_tax > $line_tax ) {
$order_item->set_total_tax( $line_tax - $discount_line_tax );
}
}
}
if ( ! empty( $shipping_items ) && is_array( $shipping_items ) && $coupon_amount > 0 ) {
foreach ( $shipping_items as $shipping_item ) {
if ( ! $shipping_item instanceof WC_Order_Item_Shipping ) {
continue;
}
if ( $coupon_amount <= 0 ) {
break;
}
$shipping_total = (float) ( is_object( $shipping_item ) && is_callable( array( $shipping_item, 'get_total' ) ) ) ? $shipping_item->get_total() : $shipping_item['total'];
$shipping_discount_total = min( $coupon_amount, $shipping_total );
$discount_line_totals += $shipping_discount_total;
$coupon_amount -= $shipping_discount_total;
if ( $coupon_amount <= 0 ) {
break;
}
$shipping_tax = (float) ( is_object( $shipping_item ) && is_callable( array( $shipping_item, 'get_total_tax' ) ) ) ? $shipping_item->get_total_tax() : $shipping_item['total_tax'];
$shipping_discount_tax = min( $coupon_amount, $shipping_tax );
$discount_line_taxes += $shipping_discount_tax;
$coupon_amount -= $shipping_discount_tax;
}
}
if ( ! empty( $fee_items ) && is_array( $fee_items ) && $coupon_amount > 0 ) {
foreach ( $fee_items as $fee_item ) {
if ( ! $fee_item instanceof WC_Order_Item_Fee || $coupon_amount < 1 ) {
continue;
}
$fee_total = (float) ( is_object( $fee_item ) && is_callable( array( $fee_item, 'get_total' ) ) ) ? $fee_item->get_total() : $fee_item['total'];
$fee_discount_total = min( $coupon_amount, $fee_total );
$discount_line_totals += $fee_discount_total;
$coupon_amount -= $fee_discount_total;
// cover fee tax.
if ( $coupon_amount <= 0 ) {
break;
}
$fee_tax = (float) ( is_object( $fee_item ) && is_callable( array( $fee_item, 'get_total_tax' ) ) ) ? $fee_item->get_total_tax() : $fee_item['total_tax'];
$fee_discount_tax = min( $coupon_amount, $fee_tax );
$discount_line_taxes += $fee_discount_tax;
$coupon_amount -= $fee_discount_tax;
}
}
}
}
}
return array(
'discount_total' => (float) $discount_line_totals,
'discount_tax' => (float) $discount_line_taxes,
);
}
/**
* Function to apply Smart Coupons discount
*
* @param float $total Cart total.
* @param WC_Cart $cart Cart object.
* @param boolean $cart_contains_subscription Is cart contains subscription.
* @param string $calculation_type The calculation type.
* @return float $total
*/
public function smart_coupons_discounted_totals( $total = 0, $cart = null, $cart_contains_subscription = false, $calculation_type = '' ) {
if ( empty( $total ) ) {
return $total;
}
$applied_coupons = ( is_object( WC()->cart ) && is_callable( array( WC()->cart, 'get_applied_coupons' ) ) ) ? WC()->cart->get_applied_coupons() : array();
$smart_coupon_credit_used = ( is_object( WC()->cart ) && isset( WC()->cart->smart_coupon_credit_used ) ) ? WC()->cart->smart_coupon_credit_used : array();
if ( ! empty( $applied_coupons ) ) {
$request_wc_ajax = ( ! empty( $_REQUEST['wc-ajax'] ) ) ? wc_clean( wp_unslash( $_REQUEST['wc-ajax'] ) ) : ''; // phpcs:ignore
$ignore_ajax_action = array( 'update_order_review', 'checkout' );
foreach ( $applied_coupons as $code ) {
if ( ! empty( $request_wc_ajax ) && in_array( $request_wc_ajax, $ignore_ajax_action, true ) && array_key_exists( $code, $smart_coupon_credit_used ) && true !== $cart_contains_subscription && ! isset( WC()->session->reload_checkout ) ) {
continue;
}
$coupon = new WC_Coupon( $code );
$discount = $this->sc_cart_get_discount_amount( $total, $coupon );
if ( ! empty( $discount ) ) {
$discount = min( $total, $discount );
$total = $total - $discount;
$this->manage_smart_coupon_credit_used( $coupon, $discount, $cart_contains_subscription, $calculation_type );
}
}
}
return $total;
}
/**
* Function to apply Smart Coupons discount after calculating tax
*
* @param WC_Cart $cart Cart object.
*/
public function smart_coupons_after_calculate_totals( $cart = null ) {
if ( empty( $cart ) || ! ( $cart instanceof WC_Cart ) ) {
return;
}
$debug_backtrace = debug_backtrace(); // phpcs:ignore
$discount_type = '';
$route = '';
if ( ! empty( $debug_backtrace ) ) {
foreach ( $debug_backtrace as $backtrace ) {
$function = ( ! empty( $backtrace['function'] ) ) ? $backtrace['function'] : '';
$class = ( ! empty( $backtrace['class'] ) ) ? $backtrace['class'] : '';
if ( 'Automattic\WooCommerce\StoreApi\Routes\V1\AbstractCartRoute' === $class && 'get_response' === $function ) {
$args = ( ! empty( $backtrace['args'] ) ) ? $backtrace['args'] : '';
if ( ! empty( $args[0] ) && is_a( $args[0], 'WP_REST_Request' ) ) {
$request = $args[0];
$route = ( $this->is_callable( $request, 'get_route' ) ) ? $request->get_route() : '';
if ( '/wc/store/v1/cart/remove-coupon' === $route ) {
$params = ( $this->is_callable( $request, 'get_params' ) ) ? $request->get_params() : array();
if ( ! empty( $params['code'] ) ) {
$coupon = new WC_Coupon( $params['code'] );
$discount_type = ( $this->is_callable( $coupon, 'get_discount_type' ) ) ? $coupon->get_discount_type() : '';
}
}
break;
}
}
}
}
$is_rest_request = ( function_exists( 'WC' ) && is_object( WC() ) && $this->is_callable( WC(), 'is_rest_api_request' ) ) ? WC()->is_rest_api_request() : null;
if ( true === $is_rest_request && '/wc/store/v1/cart/remove-coupon' === $route && 'smart_coupon' === $discount_type ) {
return;
}
// Check if AvaTax is active by checking for its main function.
if ( function_exists( 'wc_avatax' ) ) {
$wc_avatax = wc_avatax();
if ( is_callable( array( $wc_avatax, 'get_tax_handler' ) ) ) {
$ava_tax_handler = $wc_avatax->get_tax_handler();
// Check if AvaTax is doing tax calculation.
if ( is_callable( array( $ava_tax_handler, 'is_available' ) ) && true === $ava_tax_handler->is_available() ) {
// Stop discount calculation till taxes from AvaTax have been calculated.
if ( is_checkout() && ! did_action( 'wc_avatax_after_checkout_tax_calculated' ) ) {
return;
}
}
}
}
$cart_total = ( $this->is_wc_greater_than( '3.1.2' ) ) ? $cart->get_total( 'edit' ) : $cart->total;
if ( ! empty( $cart_total ) ) {
$stop_at = did_action( 'woocommerce_cart_reset' );
$stop_at = apply_filters( 'wc_sc_calculate_totals_stop_at', $stop_at, $cart );
if ( empty( $stop_at ) ) {
$stop_at = 1;
}
$cart_contains_subscription = WCS_SC_Compatibility::is_cart_contains_subscription();
$calculation_type = '';
if ( $cart_contains_subscription ) {
$stop_at++;
$calculation_type = WC_Subscriptions_Cart::get_calculation_type();
}
if ( did_action( 'smart_coupons_after_calculate_totals' ) > $stop_at ) {
return;
}
if ( 'recurring_total' === $calculation_type ) {
$total = $cart_total;
} else {
$total = $this->smart_coupons_discounted_totals( $cart_total, $cart, $cart_contains_subscription, $calculation_type );
}
if ( $this->is_wc_greater_than( '3.1.2' ) ) {
$cart_contents_total = $this->is_callable( $cart, 'get_cart_contents_total' ) ? $cart->get_cart_contents_total() : 0;
$cart_contents_tax = $this->is_callable( $cart, 'get_cart_contents_tax' ) ? $cart->get_cart_contents_tax() : 0;
$cart_contents_taxes = $this->is_callable( $cart, 'get_cart_contents_taxes' ) ? $cart->get_cart_contents_taxes() : array();
$coupon_discount_totals = $this->is_callable( $cart, 'get_coupon_discount_totals' ) ? $cart->get_coupon_discount_totals() : array();
$coupon_discount_tax_totals = $this->is_callable( $cart, 'get_coupon_discount_tax_totals' ) ? $cart->get_coupon_discount_tax_totals() : array();
$discount_total = $this->is_callable( $cart, 'get_discount_total' ) ? $cart->get_discount_total() : 0;
$discount_tax = $this->is_callable( $cart, 'get_discount_tax' ) ? $cart->get_discount_tax() : 0;
$shipping_total = $this->is_callable( $cart, 'get_shipping_total' ) ? $cart->get_shipping_total() : 0;
$shipping_tax = $this->is_callable( $cart, 'get_shipping_tax' ) ? $cart->get_shipping_tax() : 0;
$shipping_taxes = $this->is_callable( $cart, 'get_shipping_taxes' ) ? $cart->get_shipping_taxes() : array();
$fees = $this->is_callable( $cart, 'fees_api' ) && $this->is_callable( $cart->fees_api(), 'get_fees' ) ? $cart->fees_api()->get_fees() : array();
$coupon_discount = 0;
$coupon_discount_total = $discount_total;
$coupon_discount_tax = $discount_tax;
$coupon_discount_taxes = $coupon_discount_tax_totals;
$new_coupon_discount_tax = 0;
$fee_totals = array();
$fee_taxes = array();
$fee = 0;
$fee_tax = 0;
$fee_discount_total = 0;
$new_fee_discount = 0;
$shipping_discount = 0;
$shipping_discount_total = 0;
$shipping_discount_tax = 0;
$shipping_discount_taxes = array();
$credit_discount_tax = 0;
$credit_discount_taxes = array();
if ( ! empty( $fees ) ) {
foreach ( $fees as $fee_id => $fee_data ) {
$fee_totals[ $fee_id ] = ( ! empty( $fee_data->total ) ) ? $fee_data->total : 0;
$fee_taxes[ $fee_id ] = ( ! empty( $fee_data->tax ) ) ? $fee_data->tax : 0;
}
$fee = ( ! empty( $fee_totals ) ) ? array_sum( $fee_totals ) : 0;
$fee_tax = ( ! empty( $fee_taxes ) ) ? array_sum( $fee_taxes ) : 0;
}
$smart_coupon_credit_used = ( ! empty( $cart->smart_coupon_credit_used ) ) ? $cart->smart_coupon_credit_used : array();
if ( is_array( $smart_coupon_credit_used ) && ! empty( $smart_coupon_credit_used ) ) {
$total = $this->is_callable( $cart, 'get_total' ) ? $cart->get_total( 'edit' ) : $total;
$total_credit_used = array_sum( $smart_coupon_credit_used );
$cart_items = $this->is_callable( $cart, 'get_cart' ) ? $cart->get_cart() : array();
if ( is_array( $cart_items ) && ! empty( $cart_items ) ) {
// Apply discount on line total of every item.
foreach ( $cart_items as $cart_key => $item ) {
if ( $total_credit_used < 1 ) {
continue;
}
$discount_line_total = min( $item['line_total'], $total_credit_used );
$item['line_total'] -= $discount_line_total;
$total_credit_used -= $discount_line_total;
$cart_items[ $cart_key ] = $item;
}
// Apply discount on line tax of every item.
foreach ( $cart_items as $cart_key => $item ) {
if ( $total_credit_used < 1 ) {
continue;
}
if ( isset( $item['line_tax_data']['total'] ) && is_array( $item['line_tax_data']['total'] ) && ! empty( $item['line_tax_data']['total'] ) ) {
foreach ( $item['line_tax_data']['total'] as $key => $tax_item ) {
if ( $total_credit_used < 1 ) {
continue;
}
$discount_line_tax = min( $tax_item, $total_credit_used );
$item['line_tax_data']['total'][ $key ] -= $discount_line_tax;
$total_credit_used -= $discount_line_tax;
}
}
$item['line_tax'] = array_sum( $item['line_tax_data']['total'] );
$cart_items[ $cart_key ] = $item;
}
}
$cart->cart_contents = $cart_items;
foreach ( $smart_coupon_credit_used as $code => $coupon_credit ) {
if ( $coupon_credit > 0 ) {
$coupon_discount = min( $cart_contents_total, $coupon_credit );
$coupon_discount_total += $coupon_discount;
$cart_contents_total -= $coupon_discount;
$coupon_discount_totals[ $code ] = $coupon_discount;
$cart->set_cart_contents_total( $cart_contents_total );
$cart->set_coupon_discount_totals( $coupon_discount_totals );
$coupon_credit -= $coupon_discount;
if ( $coupon_credit > 0 ) {
if ( is_array( $cart_contents_taxes ) && ! empty( $cart_contents_taxes ) ) {
if ( empty( $coupon_discount_taxes[ $code ] ) ) {
$coupon_discount_taxes[ $code ] = 0;
}
if ( empty( $credit_discount_taxes[ $code ] ) ) {
$credit_discount_taxes[ $code ] = 0;
}
foreach ( $cart_contents_taxes as $index => $tax ) {
$new_coupon_discount_tax = min( $tax, $coupon_credit );
$coupon_credit -= $new_coupon_discount_tax;
$coupon_discount_taxes[ $code ] += $new_coupon_discount_tax;
$credit_discount_taxes[ $code ] += $new_coupon_discount_tax;
}
$credit_discount_tax = array_sum( $credit_discount_taxes );
$coupon_discount_tax = array_sum( $coupon_discount_taxes ) - $credit_discount_tax;
$coupon_discount_tax_totals[ $code ] = $coupon_discount_taxes[ $code ];
$cart->set_coupon_discount_tax_totals( $coupon_discount_tax_totals );
}
}
if ( $coupon_credit > 0 ) {
$shipping_discount = min( $shipping_total, $coupon_credit );
$shipping_discount_total += $shipping_discount;
$coupon_discount_totals[ $code ] += $shipping_discount;
$cart->set_coupon_discount_totals( $coupon_discount_totals );
$coupon_credit -= $shipping_discount;
}
if ( $coupon_credit > 0 ) {
if ( is_array( $shipping_taxes ) && ! empty( $shipping_taxes ) ) {
foreach ( $shipping_taxes as $index => $s_tax ) {
$shipping_discount_taxes[ $index ] = min( $s_tax, $coupon_credit );
$coupon_credit -= $shipping_discount_taxes[ $index ];
}
$shipping_discount_tax = array_sum( $shipping_discount_taxes );
$coupon_discount_tax_totals[ $code ] += $shipping_discount_tax;
$cart->set_coupon_discount_tax_totals( $coupon_discount_tax_totals );
}
}
if ( $coupon_credit > 0 && ! empty( $fee_totals ) ) {
if ( is_array( $fee_totals ) && ! empty( $fee_totals ) ) {
if ( empty( $coupon_discount_totals[ $code ] ) ) {
$coupon_discount_totals[ $code ] = 0;
}
foreach ( $fee_totals as $fee_id => $f ) {
$new_fee_discount = min( $f, $coupon_credit );
$coupon_credit -= $new_fee_discount;
$fee -= $new_fee_discount;
$fee_discount_total += $new_fee_discount;
$coupon_discount_totals[ $code ] += $new_fee_discount;
}
$cart->set_coupon_discount_totals( $coupon_discount_totals );
}
}
if ( $coupon_credit > 0 && ! empty( $fee_taxes ) ) {
if ( is_array( $fee_taxes ) && ! empty( $fee_taxes ) ) {
if ( empty( $coupon_discount_taxes[ $code ] ) ) {
$coupon_discount_taxes[ $code ] = 0;
}
if ( empty( $credit_discount_taxes[ $code ] ) ) {
$credit_discount_taxes[ $code ] = 0;
}
foreach ( $fee_taxes as $fee_id => $f_tax ) {
$new_coupon_discount_tax = min( $f_tax, $coupon_credit );
$coupon_credit -= $new_coupon_discount_tax;
$coupon_discount_taxes[ $code ] += $new_coupon_discount_tax;
$credit_discount_taxes[ $code ] += $new_coupon_discount_tax;
$coupon_discount_tax_totals[ $code ] += $new_coupon_discount_tax;
}
$credit_discount_tax = array_sum( $credit_discount_taxes );
$coupon_discount_tax = array_sum( $coupon_discount_taxes ) - $credit_discount_tax;
$cart->set_coupon_discount_tax_totals( $coupon_discount_tax_totals );
}
}
}
}
$discount_total = $coupon_discount_total + $shipping_discount_total + $fee_discount_total;
$cart->set_discount_total( $discount_total );
$discount_tax = array_sum( $coupon_discount_tax_totals );
$cart->set_discount_tax( $discount_tax );
$total_tax = $cart_contents_tax + $shipping_tax + $fee_tax;
$cart->set_total_tax( $total_tax );
$total = $cart_contents_total + array_sum( $cart_contents_taxes ) + $shipping_total + array_sum( $shipping_taxes ) + $fee + $fee_tax - array_sum( $credit_discount_taxes ) - $shipping_discount_total - $shipping_discount_tax;
}
$cart->set_total( $total );
$cart->set_session();
} else {
$cart->total = $total;
}
do_action( 'smart_coupons_after_calculate_totals' );
}
}
/**
* Function to show the discount amount applied by the store credit on the tax.
*
* @param string $coupon_html The current HTML.
* @param WC_Coupon $coupon The coupon object.
* @param string $discount_amount_html The discount amount HTML.
* @return string
*/
public function cart_totals_coupon_html( $coupon_html = '', $coupon = null, $discount_amount_html = '' ) {
$cart = ( function_exists( 'WC' ) && isset( WC()->cart ) ) ? WC()->cart : null;
if ( is_a( $cart, 'WC_Cart' ) ) {
$tax_price_display_mode = $cart->get_tax_price_display_mode();
$smart_coupon_credit_used = ( isset( $cart->smart_coupon_credit_used ) ) ? $cart->smart_coupon_credit_used : array();
$coupon_code = ( $this->is_callable( $coupon, 'get_code' ) ) ? $coupon->get_code() : '';
if ( ! empty( $coupon_code ) && array_key_exists( $coupon_code, $smart_coupon_credit_used ) ) {
$coupon_discount_tax_totals = $this->is_callable( $cart, 'get_coupon_discount_tax_totals' ) ? $cart->get_coupon_discount_tax_totals() : array();
if ( ! empty( $coupon_discount_tax_totals[ $coupon_code ] ) ) {
if ( 'excl' === $tax_price_display_mode ) {
/* translators: Discount amount applied on tax */
$coupon_html = $coupon_html . ' (' . sprintf( __( 'excludes -%s on tax', 'woocommerce-smart-coupons' ), wc_price( $coupon_discount_tax_totals[ $coupon_code ] ) ) . ')';
} else {
/* translators: Discount amount applied on tax */
$coupon_html = $coupon_html . ' (' . sprintf( __( 'includes -%s on tax', 'woocommerce-smart-coupons' ), wc_price( $coupon_discount_tax_totals[ $coupon_code ] ) ) . ')';
}
}
}
}
return $coupon_html;
}
/**
* Function to do action 'smart_coupons_after_calculate_totals' since WooCommerce Services plugin triggers 'woocommerce_cart_reset' in its function for 'woocommerce_after_calculate_totals' action causing miscalculation in did_action( 'smart_coupons_after_calculate_totals' ) hook.
*/
public function woocommerce_cart_reset() {
$cart_reset_action_count = did_action( 'woocommerce_cart_reset' );
$sc_after_calculate_action_count = did_action( 'smart_coupons_after_calculate_totals' );
// This is to match counter for 'smart_coupons_after_calculate_totals' hook with 'woocommerce_cart_reset' counter since we are using these two counters to prevent store credit being applied multiple times.
if ( $sc_after_calculate_action_count < $cart_reset_action_count ) {
do_action( 'smart_coupons_after_calculate_totals' );
}
}
/**
* Function to calculate total cart contents.
* skip the product if the product is a bundled product.
*
* @since 4.32.0
* @return int
*/
public function get_cart_contents_count() {
$total_product = 0;
$cart_data = ( isset( WC()->cart ) && is_callable( array( WC()->cart, 'get_cart' ) ) ) ? WC()->cart->get_cart() : array();
if ( ! empty( $cart_data ) ) {
foreach ( $cart_data as $data ) {
// Skip bundled products.
if ( isset( $data['stamp'] ) && isset( $data['bundled_by'] ) ) {
continue;
}
$total_product++;
}
}
return $total_product;
}
/**
* Get coupon discount amount for percentage type coupon.
*
* @param float $discount Amount this coupon has discounted.
* @param float $discounting_amount Amount the coupon is being applied to.
* @param array|null $cart_item Cart item being discounted if applicable.
* @param bool $single True if discounting a single qty item, false if its the line.
* @param WC_Coupon $coupon Coupon object.
* @return float $discount
*/
public function get_coupon_discount_amount( $discount = 0, $discounting_amount = 0, $cart_item = array(), $single = false, $coupon = object ) {
if ( is_a( $coupon, 'WC_Coupon' ) ) {
$order = ( is_a( $cart_item, 'WC_Order_Item' ) && is_callable( array( $cart_item, 'get_order' ) ) ) ? $cart_item->get_order() : null;
if ( $this->is_valid( $coupon, $order ) && is_object( $coupon ) && is_callable( array( $coupon, 'is_type' ) ) && $coupon->is_type( 'percent' ) ) {
if ( $this->is_wc_gte_30() ) {
$coupon_id = ( is_callable( array( $coupon, 'get_id' ) ) ) ? $coupon->get_id() : 0;
} else {
$coupon_id = ( ! empty( $coupon->id ) ) ? $coupon->id : 0;
}
if ( empty( $coupon_id ) ) {
return $discount;
}
$max_discount = $this->get_post_meta( $coupon_id, 'wc_sc_max_discount', true, true, $order );
if ( ! empty( $max_discount ) && is_numeric( $max_discount ) ) {
$coupon_product_ids = ( is_callable( array( $coupon, 'get_product_ids' ) ) ) ? $coupon->get_product_ids() : array();
$coupon_excluded_product_ids = ( is_callable( array( $coupon, 'get_excluded_product_ids' ) ) ) ? $coupon->get_excluded_product_ids() : array();
$coupon_category_ids = ( is_callable( array( $coupon, 'get_product_categories' ) ) ) ? $coupon->get_product_categories() : array();
$coupon_excluded_category_ids = ( is_callable( array( $coupon, 'get_excluded_product_categories' ) ) ) ? $coupon->get_excluded_product_categories() : array();
$cart_items_subtotal = 0;
$cart_contents_count = 0;
$max_discount_name = 'wc_sc_max_discount_data';
$inc_tax = wc_prices_include_tax();
$is_restricted = count( $coupon_product_ids ) > 0 || count( $coupon_excluded_product_ids ) > 0 || count( $coupon_category_ids ) > 0 || count( $coupon_excluded_category_ids ) > 0;
$is_restricted = apply_filters(
'wc_sc_is_coupon_restriction_available',
$is_restricted,
array(
'source' => $this,
'discount' => $discount,
'discounting_amount' => $discounting_amount,
'cart_item' => $cart_item,
'single' => $single,
'coupon_object' => $coupon,
)
);
if ( is_a( $cart_item, 'WC_Order_Item_Product' ) ) {
$order = $wc_cart_or_order_object = ( is_callable( array( $cart_item, 'get_order' ) ) ) ? $cart_item->get_order() : null; // phpcs:ignore
$wc_order_id = ( is_callable( array( $cart_item, 'get_order_id' ) ) ) ? $cart_item->get_order_id() : 0;
if ( empty( $wc_order_id ) ) {
return $discount;
}
$order_line_items = array();
if ( is_a( $order, 'WC_Order' ) ) {
$cart_items_subtotal = ( is_callable( array( $order, 'get_subtotal' ) ) ) ? $order->get_subtotal() : 0;
$order_line_items = ( is_callable( array( $order, 'get_items' ) ) ) ? $order->get_items() : array();
}
$max_discount_name = 'wc_sc_max_discount_data_for_' . $wc_order_id;
if ( ! empty( $order_line_items ) ) {
foreach ( $order_line_items as $order_line_item ) {
$cart_contents_count++;
}
}
$max_discount_data = function_exists( 'get_transient' ) ? get_transient( $max_discount_name ) : array();
} else {
$wc_cart = $wc_cart_or_order_object = ! empty( WC()->cart ) ? WC()->cart : null; // phpcs:ignore
$wc_session = ! empty( WC()->session ) ? WC()->session : null;
if ( ! is_a( $wc_cart, 'WC_Cart' ) ) {
return $discount;
}
if ( true === $inc_tax ) {
$cart_items_subtotal = ! empty( $wc_cart->subtotal ) ? $wc_cart->subtotal : 0;
} else {
$cart_items_subtotal = ! empty( $wc_cart->subtotal_ex_tax ) ? $wc_cart->subtotal_ex_tax : 0;
}
$max_discount_data = ( ! empty( $wc_session ) && is_a( $wc_session, 'WC_Session' ) && is_callable( array( $wc_session, 'get' ) ) ) ? $wc_session->get( $max_discount_name ) : array();
$cart_contents_count = $this->get_cart_contents_count();
}
$is_update_valid_item_count = false;
if ( empty( $max_discount_data ) || ! is_array( $max_discount_data ) ) {
$max_discount_data = array();
}
if ( empty( $max_discount_data[ $coupon_id ] ) || ! is_array( $max_discount_data[ $coupon_id ] ) ) {
$max_discount_data[ $coupon_id ] = array();
$is_update_valid_item_count = true;
$max_discount_data[ $coupon_id ]['amount'] = $max_discount;
$max_discount_data[ $coupon_id ]['count'] = $cart_contents_count;
}
if ( true === $is_restricted && class_exists( 'WC_Discounts' ) && ! empty( $wc_cart_or_order_object ) ) {
$wc_discounts = new WC_Discounts( $wc_cart_or_order_object );
$items_to_validate = array();
if ( is_callable( array( $wc_discounts, 'get_items_to_validate' ) ) ) {
$items_to_validate = $wc_discounts->get_items_to_validate();
} elseif ( is_callable( array( $wc_discounts, 'get_items' ) ) ) {
$items_to_validate = $wc_discounts->get_items();
} elseif ( ! empty( $wc_discounts->items ) && is_array( $wc_discounts->items ) ) {
$items_to_validate = $wc_discounts->items;
}
if ( is_array( $items_to_validate ) ) {
$valid_product_count = 0;
foreach ( $items_to_validate as $item ) {
$item_to_apply = clone $item; // Clone the item so changes to wc_discounts item do not affect the originals.
$valid_product_quantity = ( ! empty( $item_to_apply->quantity ) ) ? intval( $item_to_apply->quantity ) : 0;
$product = ( ! empty( $item_to_apply->product ) ) ? $item_to_apply->product : null;
$item_to_apply_object = ( ! empty( $item_to_apply->object ) ) ? $item_to_apply->object : null;
if ( 0 === $wc_discounts->get_discounted_price_in_cents( $item_to_apply ) || 0 >= $valid_product_quantity ) {
continue;
}
if ( ! $coupon->is_valid_for_product( $product, $item_to_apply_object ) && ! $coupon->is_valid_for_cart() ) {
continue;
}
// Increment if the product is not a bundled product.
$valid_product_count = ( isset( $item_to_apply_object['stamp'] ) && isset( $item_to_apply_object['bundled_by'] ) ) ? $valid_product_count : $valid_product_count + 1;
$line_subtotal = ! empty( $item_to_apply_object['line_subtotal'] ) ? intval( $item_to_apply_object['line_subtotal'] ) : 0;
if ( true === $inc_tax ) {
$line_subtotal_tax = ! empty( $item_to_apply_object['line_subtotal_tax'] ) ? intval( $item_to_apply_object['line_subtotal_tax'] ) : 0;
$cart_items_subtotal += $line_subtotal + $line_subtotal_tax;
} else {
$cart_items_subtotal += $line_subtotal;
}
}
if ( true === $is_update_valid_item_count ) {
$max_discount_data[ $coupon_id ]['count'] = $valid_product_count;
}
}
}
if ( 0 !== $cart_items_subtotal ) {
$max_discount = ! empty( $max_discount_data[ $coupon_id ]['amount'] ) ? $max_discount_data[ $coupon_id ]['amount'] : 0;
if ( $max_discount < 0 ) {
$max_discount = 0;
}
$discount = min( $max_discount, $discount );
if ( ! empty( $max_discount ) ) {
$max_discount_data[ $coupon_id ]['amount'] -= $discount;
}
$max_discount_data[ $coupon_id ]['count']--;
if ( 0 >= $max_discount_data[ $coupon_id ]['count'] ) {
unset( $max_discount_data[ $coupon_id ] );
}
if ( 'wc_sc_max_discount_data' === $max_discount_name ) {
if ( ! empty( $wc_session ) && is_a( $wc_session, 'WC_Session' ) && is_callable( array( $wc_session, 'set' ) ) ) {
$wc_session->set( $max_discount_name, $max_discount_data );
}
} elseif ( function_exists( 'set_transient' ) ) {
set_transient( $max_discount_name, $max_discount_data, DAY_IN_SECONDS );
}
}
}
}
}
return $discount;
}
/**
* Function to set default values to postmeta fields
*
* @param array $defaults Existing postmeta defaults.
* @return array
*/
public function postmeta_defaults( $defaults = array() ) {
if ( $this->is_wc_gte_32() ) {
$defaults['wc_sc_expiry_time'] = '';
}
return $defaults;
}
/**
* Function to get discount amount
*
* @param float $total The total.
* @param WC_Coupon $coupon The coupon object.
* @return float $discount
*/
public function sc_cart_get_discount_amount( $total = 0, $coupon = '' ) {
$discount = 0;
if ( is_a( $coupon, 'WC_Coupon' ) ) {
if ( $this->is_valid( $coupon ) && $coupon->is_type( 'smart_coupon' ) ) {
if ( $this->is_wc_gte_30() ) {
$coupon_code = $coupon->get_code();
$coupon_product_ids = $coupon->get_product_ids();
$coupon_product_categories = $coupon->get_product_categories();
} else {
$coupon_code = ( ! empty( $coupon->code ) ) ? $coupon->code : '';
$coupon_product_ids = ( ! empty( $coupon->product_ids ) ) ? $coupon->product_ids : array();
$coupon_product_categories = ( ! empty( $coupon->product_categories ) ) ? $coupon->product_categories : array();
}
$coupon_amount = $this->get_amount( $coupon, true );
$calculated_total = $total;
if ( count( $coupon_product_ids ) > 0 || count( $coupon_product_categories ) > 0 ) {
$discount = 0;
$line_totals = 0;
$line_taxes = 0;
$discounted_products = array();
foreach ( WC()->cart->cart_contents as $cart_item_key => $product ) {
if ( $discount >= $coupon_amount ) {
break;
}
$product_cats = wc_get_product_cat_ids( $product['product_id'] );
if ( count( $coupon_product_categories ) > 0 ) {
$continue = false;
if ( ! empty( $cart_item_key ) && ! empty( $discounted_products ) && is_array( $discounted_products ) && in_array( $cart_item_key, $discounted_products, true ) ) {
$continue = true;
}
if ( ! $continue && count( array_intersect( $product_cats, $coupon_product_categories ) ) > 0 ) {
$discounted_products[] = ( ! empty( $cart_item_key ) ) ? $cart_item_key : '';
$line_totals += $product['line_total'];
$line_taxes += $product['line_tax'];
}
}
if ( count( $coupon_product_ids ) > 0 ) {
$continue = false;
if ( ! empty( $cart_item_key ) && ! empty( $discounted_products ) && is_array( $discounted_products ) && in_array( $cart_item_key, $discounted_products, true ) ) {
$continue = true;
}
$parent_id = ( $this->is_wc_gte_30() ) ? $product['data']->get_parent_id() : $product['data']->get_parent();
if ( ! $continue && in_array( $product['product_id'], $coupon_product_ids, true ) || in_array( $product['variation_id'], $coupon_product_ids, true ) || in_array( $parent_id, $coupon_product_ids, true ) ) {
$discounted_products[] = ( ! empty( $cart_item_key ) ) ? $cart_item_key : '';
$line_totals += $product['line_total'];
$line_taxes += $product['line_tax'];
}
}
}
$calculated_total = round( ( $line_totals + $line_taxes ), wc_get_price_decimals() );
}
$discount = min( $calculated_total, $coupon_amount );
}
}
return $discount;
}
/**
* Function to manage store credit used
*
* @param WC_Coupon $coupon The coupon object.
* @param float $discount The discount.
* @param bool $cart_contains_subscription Is cart contains subscription.
* @param string $calculation_type Calculation type.
*/
public function manage_smart_coupon_credit_used( $coupon = '', $discount = 0, $cart_contains_subscription = false, $calculation_type = '' ) {
if ( is_object( $coupon ) && $coupon instanceof WC_Coupon ) {
if ( $this->is_wc_gte_30() ) {
$coupon_code = ( is_callable( array( $coupon, 'get_code' ) ) ) ? $coupon->get_code() : '';
} else {
$coupon_code = ( ! empty( $coupon->code ) ) ? $coupon->code : '';
}
$coupon_amount = $this->get_amount( $coupon, true );
if ( $cart_contains_subscription ) {
if ( WCS_SC_Compatibility::is_wcs_gte( '2.0.10' ) ) {
if ( $this->is_wc_greater_than( '3.1.2' ) ) {
$coupon_discount_totals = ( is_object( WC()->cart ) && is_callable( array( WC()->cart, 'get_coupon_discount_totals' ) ) ) ? WC()->cart->get_coupon_discount_totals() : array();
if ( ! is_array( $coupon_discount_totals ) ) {
$coupon_discount_totals = array();
}
if ( empty( $coupon_discount_totals[ $coupon_code ] ) ) {
$coupon_discount_totals[ $coupon_code ] = $discount;
} else {
$coupon_discount_totals[ $coupon_code ] += $discount;
}
( is_object( WC()->cart ) && is_callable( array( WC()->cart, 'set_coupon_discount_totals' ) ) ) ? WC()->cart->set_coupon_discount_totals( $coupon_discount_totals ) : '';
} else {
$coupon_discount_amounts = ( is_object( WC()->cart ) && isset( WC()->cart->coupon_discount_amounts ) ) ? WC()->cart->coupon_discount_amounts : array();
if ( ! is_array( $coupon_discount_amounts ) ) {
$coupon_discount_amounts = array();
}
if ( empty( $coupon_discount_amounts[ $coupon_code ] ) ) {
$coupon_discount_amounts[ $coupon_code ] = $discount;
} else {
$coupon_discount_amounts[ $coupon_code ] += $discount;
}
WC()->cart->coupon_discount_amounts = $coupon_discount_amounts;
}
} elseif ( WCS_SC_Compatibility::is_wcs_gte( '2.0.0' ) ) {
WC_Subscriptions_Coupon::increase_coupon_discount_amount( WC()->cart, $coupon_code, $discount );
} else {
WC_Subscriptions_Cart::increase_coupon_discount_amount( $coupon_code, $discount );
}
} else {
if ( $this->is_wc_greater_than( '3.1.2' ) ) {
$coupon_discount_totals = ( is_object( WC()->cart ) && is_callable( array( WC()->cart, 'get_coupon_discount_totals' ) ) ) ? WC()->cart->get_coupon_discount_totals() : array();
if ( ! is_array( $coupon_discount_totals ) ) {
$coupon_discount_totals = array();
}
if ( empty( $coupon_discount_totals[ $coupon_code ] ) ) {
$coupon_discount_totals[ $coupon_code ] = $discount;
} else {
$coupon_discount_totals[ $coupon_code ] += $discount;
}
( is_object( WC()->cart ) && is_callable( array( WC()->cart, 'set_coupon_discount_totals' ) ) ) ? WC()->cart->set_coupon_discount_totals( $coupon_discount_totals ) : '';
} else {
$coupon_discount_amounts = ( is_object( WC()->cart ) && isset( WC()->cart->coupon_discount_amounts ) ) ? WC()->cart->coupon_discount_amounts : array();
if ( ! is_array( $coupon_discount_amounts ) ) {
$coupon_discount_amounts = array();
}
if ( empty( $coupon_discount_amounts[ $coupon_code ] ) ) {
$coupon_discount_amounts[ $coupon_code ] = $discount;
} else {
$coupon_discount_amounts[ $coupon_code ] += $discount;
}
WC()->cart->coupon_discount_amounts = $coupon_discount_amounts;
}
}
if ( isset( WC()->session->reload_checkout ) ) { // reload_checkout is triggered when customer is registered from checkout.
unset( WC()->cart->smart_coupon_credit_used ); // reset store credit used data for re-calculation.
}
$smart_coupon_credit_used = ( is_object( WC()->cart ) && isset( WC()->cart->smart_coupon_credit_used ) ) ? WC()->cart->smart_coupon_credit_used : array();
if ( ! is_array( $smart_coupon_credit_used ) ) {
$smart_coupon_credit_used = array();
}
if ( empty( $smart_coupon_credit_used[ $coupon_code ] ) || ( $cart_contains_subscription && ( 'combined_total' === $calculation_type || 'sign_up_fee_total' === $calculation_type ) ) ) {
$smart_coupon_credit_used[ $coupon_code ] = $discount;
} else {
$smart_coupon_credit_used[ $coupon_code ] += $discount;
}
if ( floatval( $smart_coupon_credit_used[ $coupon_code ] ) > floatval( $coupon_amount ) ) {
$smart_coupon_credit_used[ $coupon_code ] = $coupon_amount;
}
WC()->cart->smart_coupon_credit_used = $smart_coupon_credit_used;
}
}
/**
* Apply store credit discount in order during recalculation
*
* @param float $total The total.
* @param WC_Order $order The order object.
* @return float $total
*/
public function smart_coupons_order_discounted_total( $total = 0, $order = null ) {
if ( ! $this->is_wc_gte_30() ) {
$is_proceed = check_ajax_referer( 'calc-totals', 'security', false );
if ( ! $is_proceed ) {
return $total;
}
$called_by = ( ! empty( $_POST['action'] ) ) ? wc_clean( wp_unslash( $_POST['action'] ) ) : ''; // phpcs:ignore
if ( 'woocommerce_calc_line_taxes' !== $called_by ) {
return $total;
}
}
if ( empty( $order ) ) {
return $total;
}
$coupons = ( is_object( $order ) && is_callable( array( $order, 'get_items' ) ) ) ? $order->get_items( 'coupon' ) : array();
if ( ! empty( $coupons ) ) {
foreach ( $coupons as $coupon ) {
$code = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_code' ) ) ) ? $coupon->get_code() : '';
if ( empty( $code ) ) {
continue;
}
$_coupon = new WC_Coupon( $code );
$discount_type = ( is_object( $_coupon ) && is_callable( array( $_coupon, 'get_discount_type' ) ) ) ? $_coupon->get_discount_type() : '';
if ( ! empty( $discount_type ) && 'smart_coupon' === $discount_type ) {
$discount = $this->get_amount( $_coupon, true, $order );
$applied_discount = min( $total, $discount );
if ( $this->is_wc_gte_30() ) {
$coupon->set_discount( $applied_discount );
$coupon->save();
}
$total = $total - $applied_discount;
}
}
}
return $total;
}
/**
* Add tool for clearing cache
*
* @param array $tools Existing tools.
* @return array $tools
*/
public function clear_cache_tool( $tools = array() ) {
$tools['wc_sc_clear_cache'] = array(
'name' => __( 'WooCommerce Smart Coupons Cache', 'woocommerce-smart-coupons' ),
'button' => __( 'Clear Smart Coupons Cache', 'woocommerce-smart-coupons' ),
'desc' => __( 'This tool will clear the cache created by WooCommerce Smart Coupons.', 'woocommerce-smart-coupons' ),
'callback' => array(
$this,
'clear_cache',
),
);
return $tools;
}
/**
* Clear cache
*
* @return string $message
*/
public function clear_cache() {
$message = ( is_callable( array( 'WC_SC_Act_Deact', 'clear_cache' ) ) ) ? WC_SC_Act_Deact::clear_cache() : '';
return $message;
}
/**
* WooCommerce Checkout Update Order Review
*
* @param array $post_data The post data.
*/
public function woocommerce_checkout_update_order_review( $post_data = array() ) {
wp_parse_str( $post_data, $posted_data );
if ( ! empty( $posted_data['billing_email'] ) ) {
$applied_coupons = ( is_object( WC()->cart ) && is_callable( array( WC()->cart, 'get_applied_coupons' ) ) ) ? WC()->cart->get_applied_coupons() : array();
if ( ! empty( $applied_coupons ) ) {
if ( empty( $_REQUEST['billing_email'] ) ) { // phpcs:ignore
$_REQUEST['billing_email'] = $posted_data['billing_email'];
}
foreach ( $applied_coupons as $coupon_code ) {
$coupon = new WC_Coupon( $coupon_code );
$is_valid = $this->is_user_usage_limit_valid( true, $coupon );
if ( true !== $is_valid ) {
WC()->cart->remove_coupon( $coupon_code );
/* translators: The coupon code */
wc_add_notice( sprintf( __( 'Coupon %s is valid for a new user only, hence removed.', 'woocommerce-smart-coupons' ), '' . $coupon_code . '' ), 'error' );
}
}
}
}
}
/**
* Function to return validity of Store Credit / Gift Certificate
*
* @param boolean $valid Coupon validity.
* @param WC_Coupon $coupon Coupon object.
* @param WC_Discounts $discounts Discounts object.
* @return boolean $valid TRUE if smart coupon valid, FALSE otherwise
*/
public function is_smart_coupon_valid( $valid, $coupon, $discounts = null ) {
if ( $this->is_wc_gte_30() ) {
$discount_type = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_discount_type' ) ) ) ? $coupon->get_discount_type() : '';
$coupon_code = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_code' ) ) ) ? $coupon->get_code() : '';
} else {
$discount_type = ( ! empty( $coupon->discount_type ) ) ? $coupon->discount_type : '';
$coupon_code = ( ! empty( $coupon->code ) ) ? $coupon->code : '';
}
$coupon_amount = $this->get_amount( $coupon, true );
if ( 'smart_coupon' !== $discount_type ) {
return $valid;
}
$applied_coupons = ( is_object( WC()->cart ) && is_callable( array( WC()->cart, 'get_applied_coupons' ) ) ) ? WC()->cart->get_applied_coupons() : array();
if ( empty( $applied_coupons ) || ( ! empty( $applied_coupons ) && ! in_array( $coupon_code, $applied_coupons, true ) ) ) {
return $valid;
}
if ( is_wc_endpoint_url( 'order-received' ) ) {
return $valid;
}
$is_valid_coupon_amount = ( $coupon_amount <= 0 ) ? false : true;
$is_valid_coupon_amount = apply_filters(
'wc_sc_validate_coupon_amount',
$is_valid_coupon_amount,
array(
'coupon' => $coupon,
'discounts' => $discounts,
'coupon_amount' => $coupon_amount,
'discount_type' => $discount_type,
'coupon_code' => $coupon_code,
)
);
if ( $valid && ! $is_valid_coupon_amount ) {
WC()->cart->remove_coupon( $coupon_code );
/* translators: The coupon code */
wc_add_notice( sprintf( __( 'Coupon removed. There is no credit remaining in %s.', 'woocommerce-smart-coupons' ), '' . $coupon_code . '' ), 'error' );
return false;
}
return $valid;
}
/**
* Strict check if user is valid as per usage limit
*
* @param boolean $is_valid Is valid.
* @param WC_Coupon $coupon The coupon object.
* @param WC_Discounts $discounts The discounts object.
* @return boolean
* @throws Exception When coupon is not valid as per the usage limit.
*/
public function is_user_usage_limit_valid( $is_valid = false, $coupon = null, $discounts = null ) {
if ( is_admin() && ( ! defined( 'DOING_AJAX' ) || DOING_AJAX !== true ) ) {
return $is_valid;
}
if ( true !== $is_valid ) {
return $is_valid;
}
global $wpdb;
if ( $this->is_wc_gte_30() ) {
$coupon_id = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_id' ) ) ) ? $coupon->get_id() : 0;
} else {
$coupon_id = ( ! empty( $coupon->id ) ) ? $coupon->id : 0;
}
$for_new_user = ( $this->is_callable( $coupon, 'get_meta' ) ) ? $coupon->get_meta( 'sc_restrict_to_new_user' ) : get_post_meta( $coupon_id, 'sc_restrict_to_new_user', true );
if ( 'yes' === $for_new_user ) {
$failed_notice = __( 'This coupon is valid for the first order only.', 'woocommerce-smart-coupons' );
$user_id_1 = 0;
$user_id_2 = 0;
$user_id_3 = 0;
$current_user = wp_get_current_user();
$email = ( ! empty( $current_user->data->user_email ) ) ? $current_user->data->user_email : '';
$email = ( ! empty( $_REQUEST['billing_email'] ) ) ? sanitize_email( wp_unslash( $_REQUEST['billing_email'] ) ) : $email; // phpcs:ignore
$valid_order_statuses = get_option( 'wc_sc_valid_order_statuses_for_coupon_auto_generation', array() );
$statuses_placeholder = array();
if ( ! empty( $valid_order_statuses ) ) {
$valid_order_statuses = array_map(
function( $status ) {
return 'wc-' . $status;
},
$valid_order_statuses
);
$how_many_statuses = count( $valid_order_statuses );
$statuses_placeholder = array_fill( 0, $how_many_statuses, '%s' );
}
if ( ! empty( $email ) && is_email( $email ) ) {
$order_id = wp_cache_get( 'wc_sc_order_id_by_billing_email_' . sanitize_key( $email ), 'woocommerce_smart_coupons' );
if ( false === $order_id ) {
if ( $this->is_hpos() ) {
$query = $wpdb->prepare(
"SELECT id
FROM {$wpdb->prefix}wc_orders
WHERE billing_email = %s",
$email
);
} else {
$query = $wpdb->prepare(
"SELECT ID
FROM $wpdb->posts AS p
LEFT JOIN $wpdb->postmeta AS pm
ON ( p.ID = pm.post_id AND pm.meta_key = %s )
WHERE p.post_type = %s
AND pm.meta_value = %s",
'_billing_email',
'shop_order',
$email
);
}
if ( ! empty( $valid_order_statuses ) && ! empty( $statuses_placeholder ) ) {
// phpcs:disable
if ( $this->is_hpos() ) {
$query .= $wpdb->prepare(
' AND status IN (' . implode( ',', $statuses_placeholder ) . ')',
$valid_order_statuses
);
} else {
$query .= $wpdb->prepare(
' AND p.post_status IN (' . implode( ',', $statuses_placeholder ) . ')',
$valid_order_statuses
);
}
// phpcs:enable
}
$order_id = $wpdb->get_var( $query ); // phpcs:ignore
wp_cache_set( 'wc_sc_order_id_by_billing_email_' . sanitize_key( $email ), $order_id, 'woocommerce_smart_coupons' );
$this->maybe_add_cache_key( 'wc_sc_order_id_by_billing_email_' . sanitize_key( $email ) );
}
if ( ! empty( $order_id ) ) {
if ( defined( 'WC_DOING_AJAX' ) && WC_DOING_AJAX === true ) {
$is_valid = false;
} else {
throw new Exception( $failed_notice );
}
}
$user_id_1 = wp_cache_get( 'wc_sc_user_id_by_user_email_' . sanitize_key( $email ), 'woocommerce_smart_coupons' );
if ( false === $user_id_1 ) {
$user_id_1 = $wpdb->get_var( // phpcs:ignore
$wpdb->prepare(
"SELECT ID
FROM {$wpdb->base_prefix}users
WHERE user_email = %s",
$email
)
);
wp_cache_set( 'wc_sc_user_id_by_user_email_' . sanitize_key( $email ), $user_id_1, 'woocommerce_smart_coupons' );
$this->maybe_add_cache_key( 'wc_sc_user_id_by_user_email_' . sanitize_key( $email ) );
}
$user_id_2 = wp_cache_get( 'wc_sc_user_id_by_billing_email_' . sanitize_key( $email ), 'woocommerce_smart_coupons' );
if ( false === $user_id_2 ) {
$user_id_2 = $wpdb->get_var( // phpcs:ignore
$wpdb->prepare(
"SELECT user_id
FROM {$wpdb->base_prefix}usermeta
WHERE meta_key = %s
AND meta_value = %s",
'billing_email',
$email
)
);
wp_cache_set( 'wc_sc_user_id_by_billing_email_' . sanitize_key( $email ), $user_id_2, 'woocommerce_smart_coupons' );
$this->maybe_add_cache_key( 'wc_sc_user_id_by_billing_email_' . sanitize_key( $email ) );
}
}
$user_id_3 = get_current_user_id();
$user_ids = array( $user_id_1, $user_id_2, $user_id_3 );
$user_ids = array_unique( array_filter( $user_ids ) );
if ( ! empty( $user_ids ) ) {
$unique_user_ids = array_unique( $user_ids );
$order_id = wp_cache_get( 'wc_sc_order_for_user_id_' . implode( '_', $unique_user_ids ), 'woocommerce_smart_coupons' );
if ( false === $order_id ) {
if ( $this->is_hpos() ) {
$query = $wpdb->prepare(
"SELECT id
FROM {$wpdb->prefix}wc_orders
WHERE %d",
1
);
} else {
$query = $wpdb->prepare(
"SELECT ID
FROM $wpdb->posts AS p
LEFT JOIN $wpdb->postmeta AS pm
ON ( p.ID = pm.post_id AND pm.meta_key = %s )
WHERE p.post_type = %s",
'_customer_user',
'shop_order'
);
}
if ( ! empty( $valid_order_statuses ) && ! empty( $statuses_placeholder ) ) {
// phpcs:disable
if ( $this->is_hpos() ) {
$query .= $wpdb->prepare(
' AND status IN (' . implode( ',', $statuses_placeholder ) . ')',
$valid_order_statuses
);
} else {
$query .= $wpdb->prepare(
' AND p.post_status IN (' . implode( ',', $statuses_placeholder ) . ')',
$valid_order_statuses
);
}
// phpcs:enable
}
$how_many_user_ids = count( $user_ids );
// phpcs:disable
if ( $this->is_hpos() ) {
$id_placeholder = array_fill( 0, $how_many_user_ids, '%d' );
$query .= $wpdb->prepare(
' AND customer_id IN (' . implode( ',', $id_placeholder ) . ')',
$user_ids
);
} else {
$id_placeholder = array_fill( 0, $how_many_user_ids, '%s' );
$query .= $wpdb->prepare(
' AND pm.meta_value IN (' . implode( ',', $id_placeholder ) . ')',
$user_ids
);
}
// phpcs:enable
$order_id = $wpdb->get_var( $query ); // phpcs:ignore
wp_cache_set( 'wc_sc_order_for_user_id_' . implode( '_', $unique_user_ids ), $order_id, 'woocommerce_smart_coupons' );
$this->maybe_add_cache_key( 'wc_sc_order_for_user_id_' . implode( '_', $unique_user_ids ) );
}
if ( ! empty( $order_id ) ) {
if ( defined( 'WC_DOING_AJAX' ) && WC_DOING_AJAX === true ) {
$is_valid = false;
} else {
throw new Exception( $failed_notice );
}
}
}
}
return $is_valid;
}
/**
* Locate template for Smart Coupons
*
* @param string $template_name The template name.
* @param mixed $template Default template.
* @return mixed $template
*/
public function locate_template_for_smart_coupons( $template_name = '', $template = '' ) {
$default_path = untrailingslashit( plugin_dir_path( WC_SC_PLUGIN_FILE ) ) . '/templates/';
$plugin_base_dir = substr( plugin_basename( WC_SC_PLUGIN_FILE ), 0, strpos( plugin_basename( WC_SC_PLUGIN_FILE ), '/' ) + 1 );
// Look within passed path within the theme - this is priority.
$template = locate_template(
array(
'woocommerce/' . $plugin_base_dir . $template_name,
$plugin_base_dir . $template_name,
$template_name,
)
);
// Get default template.
if ( ! $template ) {
$template = $default_path . $template_name;
}
return $template;
}
/**
* Function to get template base directory for Smart Coupons' email templates
*
* @param string $template_name Template name.
* @return string $template_base_dir Base directory for Smart Coupons' email templates.
*/
public function get_template_base_dir( $template_name = '' ) {
$template_base_dir = '';
$plugin_base_dir = substr( plugin_basename( WC_SC_PLUGIN_FILE ), 0, strpos( plugin_basename( WC_SC_PLUGIN_FILE ), '/' ) + 1 );
$wc_sc_base_dir = 'woocommerce/' . $plugin_base_dir;
// First locate the template in woocommerce/woocommerce-smart-coupons folder of active theme.
$template = locate_template(
array(
$wc_sc_base_dir . $template_name,
)
);
if ( ! empty( $template ) ) {
$template_base_dir = $wc_sc_base_dir;
} else {
// If not found then locate the template in woocommerce-smart-coupons folder of active theme.
$template = locate_template(
array(
$plugin_base_dir . $template_name,
)
);
if ( ! empty( $template ) ) {
$template_base_dir = $plugin_base_dir;
}
}
$template_base_dir = apply_filters( 'wc_sc_template_base_dir', $template_base_dir, $template_name );
return $template_base_dir;
}
/**
* Check whether credit is sent or not
*
* @param string $email_id The email address.
* @param WC_Coupon $coupon The coupon object.
* @return boolean
*/
public function is_credit_sent( $email_id, $coupon ) {
global $smart_coupon_codes;
if ( isset( $smart_coupon_codes[ $email_id ] ) && count( $smart_coupon_codes[ $email_id ] ) > 0 ) {
if ( $this->is_wc_gte_30() ) {
$coupon_id = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_id' ) ) ) ? $coupon->get_id() : 0;
} else {
$coupon_id = ( ! empty( $coupon->id ) ) ? $coupon->id : 0;
}
foreach ( $smart_coupon_codes[ $email_id ] as $generated_coupon_details ) {
if ( $generated_coupon_details['parent'] === $coupon_id ) {
return true;
}
}
}
return false;
}
/**
* Generate unique string to be used as coupon code. Also add prefix or suffix if already set
*
* @param string $email The email address.
* @param WC_Coupon $coupon The coupon object.
* @return string $unique_code
*/
public function generate_unique_code( $email = '', $coupon = '' ) {
$unique_code = '';
srand( (double) microtime( true ) * 1000000 ); // phpcs:ignore
$coupon_code_length = $this->get_coupon_code_length();
$chars = array_diff( array_merge( range( 'a', 'z' ), range( '0', '9' ) ), array( 'a', 'e', 'i', 'o', 'u' ) );
$chars = apply_filters(
'wc_sc_coupon_code_allowed_characters',
array_values( $chars ),
array(
'source' => $this,
'email' => $email,
'coupon_object' => $coupon,
'coupon_code_length' => $coupon_code_length,
)
);
$numbers = array_values( array_filter( $chars, 'is_numeric' ) );
$alphabets = ( count( $chars ) !== count( $numbers ) ) ? array_values( array_diff( $chars, $numbers ) ) : array();
if ( empty( $numbers ) || empty( $alphabets ) ) {
$chars = array_values( array_merge( $alphabets, $numbers ) );
for ( $rand = 1; $rand <= $coupon_code_length; $rand++ ) {
$random = rand( 0, count( $chars ) - 1 ); // phpcs:ignore
$unique_code .= $chars[ $random ];
}
} else {
for ( $rand = 1, $char_count = 0, $num_count = 0; $rand <= $coupon_code_length; $rand++ ) {
if ( $char_count >= 2 ) {
$random = rand( 0, count( $numbers ) - 1 ); // phpcs:ignore
$unique_code .= $numbers[ $random ];
$char_count = 0;
$num_count++;
} elseif ( $num_count >= 1 ) {
$random = rand( 0, count( $alphabets ) - 1 ); // phpcs:ignore
$unique_code .= $alphabets[ $random ];
$num_count = 0;
$char_count++;
} else {
$random = rand( 0, count( $chars ) - 1 ); // phpcs:ignore
$selected_char = $chars[ $random ];
$unique_code .= $selected_char;
if ( is_numeric( $selected_char ) ) {
$num_count++;
} else {
$char_count++;
}
}
}
}
if ( $this->is_wc_gte_30() ) {
$coupon_id = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_id' ) ) ) ? $coupon->get_id() : 0;
} else {
$coupon_id = ( ! empty( $coupon->id ) ) ? $coupon->id : 0;
}
if ( $this->is_callable( $coupon, 'get_meta' ) ) {
if ( 'yes' === $coupon->get_meta( 'auto_generate_coupon' ) ) {
$prefix = $coupon->get_meta( 'coupon_title_prefix' );
$suffix = $coupon->get_meta( 'coupon_title_suffix' );
$unique_code = $prefix . $unique_code . $suffix;
}
} else {
if ( ! empty( $coupon_id ) && get_post_meta( $coupon_id, 'auto_generate_coupon', true ) === 'yes' ) {
$prefix = get_post_meta( $coupon_id, 'coupon_title_prefix', true );
$suffix = get_post_meta( $coupon_id, 'coupon_title_suffix', true );
$unique_code = $prefix . $unique_code . $suffix;
}
}
return apply_filters(
'wc_sc_generate_unique_coupon_code',
$unique_code,
array(
'email' => $email,
'coupon' => $coupon,
)
);
}
/**
* Function for generating Gift Certificate
*
* @param mixed $email The email address.
* @param float $amount The amount.
* @param int $order_id The order id.
* @param WC_Coupon $coupon The coupon object.
* @param string $discount_type The discount type.
* @param array $gift_certificate_receiver_name Receiver name.
* @param string $message_from_sender Message from sender.
* @param string $gift_certificate_sender_name Sender name.
* @param string $gift_certificate_sender_email Sender email.
* @param string $sending_timestamp timestamp for scheduled sending.
* @return array of generated coupon details
*/
public function generate_smart_coupon( $email, $amount, $order_id = '', $coupon = '', $discount_type = 'smart_coupon', $gift_certificate_receiver_name = '', $message_from_sender = '', $gift_certificate_sender_name = '', $gift_certificate_sender_email = '', $sending_timestamp = '' ) {
return $this->generate_smart_coupon_action( $email, $amount, $order_id, $coupon, $discount_type, $gift_certificate_receiver_name, $message_from_sender, $gift_certificate_sender_name, $gift_certificate_sender_email, $sending_timestamp );
}
/**
* Function for generating Gift Certificate
*
* @param mixed $email The email address.
* @param float $amount The amount.
* @param int $order_id The order id.
* @param WC_Coupon $coupon The coupon object.
* @param string $discount_type The discount type.
* @param array $gift_certificate_receiver_name Receiver name.
* @param string $message_from_sender Message from sender.
* @param string $gift_certificate_sender_name Sender name.
* @param string $gift_certificate_sender_email Sender email.
* @param string $sending_timestamp timestamp for scheduled sending.
* @return array $smart_coupon_codes associative array containing generated coupon details
*/
public function generate_smart_coupon_action( $email, $amount, $order_id = '', $coupon = '', $discount_type = 'smart_coupon', $gift_certificate_receiver_name = '', $message_from_sender = '', $gift_certificate_sender_name = '', $gift_certificate_sender_email = '', $sending_timestamp = '' ) {
if ( '' === $email ) {
return false;
}
global $smart_coupon_codes;
$order_id = ( ! empty( $order_id ) ) ? absint( $order_id ) : 0;
$order = ( function_exists( 'wc_get_order' ) && ! empty( $order_id ) ) ? wc_get_order( $order_id ) : null;
$is_callable_order_get_meta = $this->is_callable( $order, 'get_meta' );
$is_callable_coupon_get_meta = $this->is_callable( $coupon, 'get_meta' );
if ( $this->is_wc_gte_30() ) {
$coupon_id = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_id' ) ) ) ? $coupon->get_id() : 0;
$is_free_shipping = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_free_shipping' ) ) ) ? ( ( $coupon->get_free_shipping() ) ? 'yes' : 'no' ) : '';
$discount_type = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_discount_type' ) ) ) ? $coupon->get_discount_type() : '';
$expiry_date = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_date_expires' ) ) ) ? $coupon->get_date_expires() : '';
$coupon_product_ids = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_product_ids' ) ) ) ? $coupon->get_product_ids() : '';
$coupon_product_categories = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_product_categories' ) ) ) ? $coupon->get_product_categories() : '';
$coupon_excluded_product_ids = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_excluded_product_ids' ) ) ) ? $coupon->get_excluded_product_ids() : '';
$coupon_excluded_product_categories = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_excluded_product_categories' ) ) ) ? $coupon->get_excluded_product_categories() : '';
$coupon_minimum_amount = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_minimum_amount' ) ) ) ? $coupon->get_minimum_amount() : '';
$coupon_maximum_amount = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_maximum_amount' ) ) ) ? $coupon->get_maximum_amount() : '';
$coupon_usage_limit = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_usage_limit' ) ) ) ? $coupon->get_usage_limit() : '';
$coupon_usage_limit_per_user = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_usage_limit_per_user' ) ) ) ? $coupon->get_usage_limit_per_user() : '';
$coupon_limit_usage_to_x_items = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_limit_usage_to_x_items' ) ) ) ? $coupon->get_limit_usage_to_x_items() : '';
$is_exclude_sale_items = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_exclude_sale_items' ) ) ) ? ( ( $coupon->get_exclude_sale_items() ) ? 'yes' : 'no' ) : '';
$is_individual_use = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_individual_use' ) ) ) ? ( ( $coupon->get_individual_use() ) ? 'yes' : 'no' ) : '';
} else {
$coupon_id = ( ! empty( $coupon->id ) ) ? $coupon->id : 0;
$is_free_shipping = ( ! empty( $coupon->free_shipping ) ) ? $coupon->free_shipping : '';
$discount_type = ( ! empty( $coupon->discount_type ) ) ? $coupon->discount_type : '';
$expiry_date = ( ! empty( $coupon->expiry_date ) ) ? $coupon->expiry_date : '';
$coupon_product_ids = ( ! empty( $coupon->product_ids ) ) ? $coupon->product_ids : '';
$coupon_product_categories = ( ! empty( $coupon->product_categories ) ) ? $coupon->product_categories : '';
$coupon_excluded_product_ids = ( ! empty( $coupon->exclude_product_ids ) ) ? $coupon->exclude_product_ids : '';
$coupon_excluded_product_categories = ( ! empty( $coupon->exclude_product_categories ) ) ? $coupon->exclude_product_categories : '';
$coupon_minimum_amount = ( ! empty( $coupon->minimum_amount ) ) ? $coupon->minimum_amount : '';
$coupon_maximum_amount = ( ! empty( $coupon->maximum_amount ) ) ? $coupon->maximum_amount : '';
$coupon_usage_limit = ( ! empty( $coupon->usage_limit ) ) ? $coupon->usage_limit : '';
$coupon_usage_limit_per_user = ( ! empty( $coupon->usage_limit_per_user ) ) ? $coupon->usage_limit_per_user : '';
$coupon_limit_usage_to_x_items = ( ! empty( $coupon->limit_usage_to_x_items ) ) ? $coupon->limit_usage_to_x_items : '';
$is_exclude_sale_items = ( ! empty( $coupon->exclude_sale_items ) ) ? $coupon->exclude_sale_items : '';
$is_individual_use = ( ! empty( $coupon->individual_use ) ) ? $coupon->individual_use : '';
}
if ( ! is_array( $email ) ) {
$emails = array( $email => 1 );
} else {
$temp_email = ( true === $is_callable_order_get_meta ) ? $order->get_meta( 'temp_gift_card_receivers_emails' ) : get_post_meta( $order_id, 'temp_gift_card_receivers_emails', true );
if ( ! empty( $temp_email ) && count( $temp_email ) > 0 ) {
$email = $temp_email;
}
$emails = ( ! empty( $coupon_id ) ) ? array_count_values( $email[ $coupon_id ] ) : array();
}
if ( ! empty( $order_id ) ) {
$receivers_messages = ( true === $is_callable_order_get_meta ) ? $order->get_meta( 'gift_receiver_message' ) : get_post_meta( $order_id, 'gift_receiver_message', true );
$schedule_gift_sending = ( true === $is_callable_order_get_meta ) ? $order->get_meta( 'wc_sc_schedule_gift_sending' ) : get_post_meta( $order_id, 'wc_sc_schedule_gift_sending', true );
$sending_timestamps = ( true === $is_callable_order_get_meta ) ? $order->get_meta( 'gift_sending_timestamp' ) : get_post_meta( $order_id, 'gift_sending_timestamp', true );
}
foreach ( $emails as $email_id => $qty ) {
if ( $this->is_credit_sent( $email_id, $coupon ) ) {
continue;
}
$smart_coupon_code = $this->generate_unique_code( $email_id, $coupon );
$coupon_post = ( ! empty( $coupon_id ) ) ? get_post( $coupon_id ) : new stdClass();
$smart_coupon_args = array(
'post_title' => strtolower( $smart_coupon_code ),
'post_excerpt' => ( ! empty( $coupon_post->post_excerpt ) ) ? $coupon_post->post_excerpt : '',
'post_content' => '',
'post_status' => 'publish',
'post_author' => 1,
'post_type' => 'shop_coupon',
'post_parent' => ! empty( $coupon_id ) ? absint( $coupon_id ) : 0,
);
$should_schedule = isset( $schedule_gift_sending ) && 'yes' === $schedule_gift_sending && $this->is_valid_timestamp( $sending_timestamp ) ? true : false;
if ( $should_schedule ) {
$smart_coupon_args['post_date_gmt'] = gmdate( 'Y-m-d H:i:s', $sending_timestamp );
$smart_coupon_args['post_date'] = gmdate( 'Y-m-d H:i:s', ( $sending_timestamp + $this->wc_timezone_offset() ) );
}
$smart_coupon = new WC_Coupon( $smart_coupon_args['post_title'] );
$smart_coupon->set_description( $smart_coupon_args['post_excerpt'] );
if ( $this->is_wc_greater_than( '6.1.2' ) && $this->is_callable( $smart_coupon, 'set_status' ) ) {
$smart_coupon->set_status( $smart_coupon_args['post_status'] );
}
$smart_coupon_id = $smart_coupon->save();
if ( ! empty( $smart_coupon_id ) ) {
$smart_coupon_args = array_diff_key( $smart_coupon_args, array_flip( array( 'post_excerpt', 'post_title', 'post_status', 'post_type' ) ) );
$smart_coupon_args['ID'] = $smart_coupon_id;
wp_update_post( $smart_coupon_args );
}
$smart_coupon_id = absint( $smart_coupon_id );
$smart_coupon = new WC_Coupon( $smart_coupon );
$is_callable_smart_coupon_update_meta = $this->is_callable( $smart_coupon, 'update_meta_data' );
$type = ( ! empty( $discount_type ) ) ? $discount_type : 'smart_coupon';
$individual_use = ( ! empty( $is_individual_use ) ) ? $is_individual_use : 'no';
$minimum_amount = ( ! empty( $coupon_minimum_amount ) ) ? $coupon_minimum_amount : '';
$maximum_amount = ( ! empty( $coupon_maximum_amount ) ) ? $coupon_maximum_amount : '';
$product_ids = ( ! empty( $coupon_product_ids ) ) ? implode( ',', $coupon_product_ids ) : '';
$exclude_product_ids = ( ! empty( $coupon_excluded_product_ids ) ) ? implode( ',', $coupon_excluded_product_ids ) : '';
$usage_limit = ( ! empty( $coupon_usage_limit ) ) ? $coupon_usage_limit : '';
$usage_limit_per_user = ( ! empty( $coupon_usage_limit_per_user ) ) ? $coupon_usage_limit_per_user : '';
$limit_usage_to_x_items = ( ! empty( $coupon_limit_usage_to_x_items ) ) ? $coupon_limit_usage_to_x_items : '';
$free_shipping = ( ! empty( $is_free_shipping ) ) ? $is_free_shipping : 'no';
$product_categories = ( ! empty( $coupon_product_categories ) ) ? $coupon_product_categories : array();
$exclude_product_categories = ( ! empty( $coupon_excluded_product_categories ) ) ? $coupon_excluded_product_categories : array();
$sc_coupon_validity = ( true === $is_callable_coupon_get_meta ) ? $coupon->get_meta( 'sc_coupon_validity' ) : ( ( ! empty( $coupon_id ) ) ? get_post_meta( $coupon_id, 'sc_coupon_validity', true ) : '' );
$is_disable_email_restriction = ( true === $is_callable_coupon_get_meta ) ? $coupon->get_meta( 'sc_disable_email_restriction' ) : ( ( ! empty( $coupon_id ) ) ? get_post_meta( $coupon_id, 'sc_disable_email_restriction', true ) : '' );
$sc_restrict_to_new_user = ( true === $is_callable_coupon_get_meta ) ? $coupon->get_meta( 'sc_restrict_to_new_user' ) : get_post_meta( $coupon_id, 'sc_restrict_to_new_user', true );
$wc_sc_max_discount = $this->get_post_meta( $coupon_id, 'wc_sc_max_discount', true, true, $order );
if ( $this->is_wc_gte_30() && $expiry_date instanceof WC_DateTime ) {
$expiry_date = ( is_callable( array( $expiry_date, 'getTimestamp' ) ) ) ? $expiry_date->getTimestamp() : null;
} elseif ( ! is_int( $expiry_date ) ) {
$expiry_date = $this->strtotime( $expiry_date );
}
if ( ! empty( $coupon_id ) && ! empty( $sc_coupon_validity ) ) {
$is_parent_coupon_expired = ( ! empty( $expiry_date ) && ( $expiry_date < time() ) ) ? true : false;
if ( ! $is_parent_coupon_expired ) {
$validity_suffix = ( true === $is_callable_coupon_get_meta ) ? $coupon->get_meta( 'validity_suffix' ) : get_post_meta( $coupon_id, 'validity_suffix', true );
// In case of scheduled coupon, expiry date is calculated from scheduled publish date.
if ( isset( $smart_coupon_args['post_date_gmt'] ) ) {
$expiry_date = $this->strtotime( $smart_coupon_args['post_date_gmt'] . "+$sc_coupon_validity $validity_suffix" );
} else {
$expiry_date = $this->strtotime( "+$sc_coupon_validity $validity_suffix" );
}
}
}
if ( $this->is_wc_gte_30() ) {
$expiry_date = $this->get_date_expires_value( $expiry_date );
if ( true === $is_callable_smart_coupon_update_meta ) {
$smart_coupon->set_date_expires( $expiry_date );
} else {
update_post_meta( $smart_coupon_id, 'date_expires', $expiry_date );
}
} else {
$expiry_date = ( ! empty( $expiry_date ) ) ? gmdate( 'Y-m-d', intval( $expiry_date ) + $this->wc_timezone_offset() ) : '';
if ( true === $is_callable_smart_coupon_update_meta ) {
$smart_coupon->update_meta_data( 'expiry_date', $expiry_date );
} else {
update_post_meta( $smart_coupon_id, 'expiry_date', $expiry_date );
}
}
if ( 'smart_coupon' === $type ) {
$this->update_post_meta( $smart_coupon_id, 'wc_sc_original_amount', $amount, false, $order );
}
if ( true === $is_callable_smart_coupon_update_meta ) {
$product_ids = ( ! is_array( $product_ids ) ) ? explode( ',', $product_ids ) : $product_ids; // set_product_ids expects an array.
$exclude_product_ids = ( ! is_array( $exclude_product_ids ) ) ? explode( ',', $exclude_product_ids ) : $exclude_product_ids; // set_excluded_product_ids expects an array.
$smart_coupon->set_amount( $amount );
$smart_coupon->set_excluded_product_ids( $exclude_product_ids );
$smart_coupon->set_excluded_product_categories( $exclude_product_categories );
$smart_coupon->set_discount_type( $type );
$smart_coupon->set_individual_use( $this->wc_string_to_bool( $individual_use ) );
$smart_coupon->set_minimum_amount( $minimum_amount );
$smart_coupon->set_maximum_amount( $maximum_amount );
$smart_coupon->set_product_ids( $product_ids );
$smart_coupon->set_usage_limit( $usage_limit );
$smart_coupon->set_usage_limit_per_user( $usage_limit_per_user );
$smart_coupon->set_limit_usage_to_x_items( $limit_usage_to_x_items );
$smart_coupon->set_free_shipping( $this->wc_string_to_bool( $free_shipping ) );
$smart_coupon->set_product_categories( $product_categories );
$smart_coupon->set_exclude_sale_items( $this->wc_string_to_bool( $is_exclude_sale_items ) );
$smart_coupon->update_meta_data( 'sc_restrict_to_new_user', $sc_restrict_to_new_user );
if ( ! empty( $order_id ) ) {
$smart_coupon->update_meta_data( 'generated_from_order_id', $order_id );
}
if ( empty( $is_disable_email_restriction ) || 'no' === $is_disable_email_restriction ) {
// Update customer_email now if coupon is not scheduled otherwise it would be updated by action scheduler later on.
if ( ! $should_schedule ) {
$smart_coupon->set_email_restrictions( array( $email_id ) );
}
}
} else {
update_post_meta( $smart_coupon_id, 'discount_type', $type );
update_post_meta( $smart_coupon_id, 'coupon_amount', $amount );
update_post_meta( $smart_coupon_id, 'individual_use', $individual_use );
update_post_meta( $smart_coupon_id, 'minimum_amount', $minimum_amount );
update_post_meta( $smart_coupon_id, 'maximum_amount', $maximum_amount );
update_post_meta( $smart_coupon_id, 'product_ids', $product_ids );
update_post_meta( $smart_coupon_id, 'exclude_product_ids', $exclude_product_ids );
update_post_meta( $smart_coupon_id, 'usage_limit', $usage_limit );
update_post_meta( $smart_coupon_id, 'usage_limit_per_user', $usage_limit_per_user );
update_post_meta( $smart_coupon_id, 'limit_usage_to_x_items', $limit_usage_to_x_items );
update_post_meta( $smart_coupon_id, 'free_shipping', $free_shipping );
update_post_meta( $smart_coupon_id, 'product_categories', $product_categories );
update_post_meta( $smart_coupon_id, 'exclude_product_categories', $exclude_product_categories );
update_post_meta( $smart_coupon_id, 'exclude_sale_items', $is_exclude_sale_items );
update_post_meta( $smart_coupon_id, 'sc_restrict_to_new_user', $sc_restrict_to_new_user );
if ( ! empty( $order_id ) ) {
update_post_meta( $smart_coupon_id, 'generated_from_order_id', $order_id );
}
if ( empty( $is_disable_email_restriction ) || 'no' === $is_disable_email_restriction ) {
// Update customer_email now if coupon is not scheduled otherwise it would be updated by action scheduler later on.
if ( ! $should_schedule ) {
update_post_meta( $smart_coupon_id, 'customer_email', array( $email_id ) );
}
}
}
if ( ! $this->is_wc_gte_30() ) {
$apply_before_tax = ( ! empty( $coupon->apply_before_tax ) ) ? $coupon->apply_before_tax : 'no';
if ( true === $is_callable_smart_coupon_update_meta ) {
$smart_coupon->update_meta_data( 'apply_before_tax', $apply_before_tax );
} else {
update_post_meta( $smart_coupon_id, 'apply_before_tax', $apply_before_tax );
}
}
// Add terms to auto-generated if found in parent coupon.
$coupon_terms = get_the_terms( $coupon_id, 'sc_coupon_category' );
if ( ! empty( $coupon_terms ) ) {
$term_ids = array_column( $coupon_terms, 'term_id' );
wp_set_object_terms( $smart_coupon_id, $term_ids, 'sc_coupon_category', false );
}
if ( ! empty( $wc_sc_max_discount ) ) {
$this->update_post_meta( $smart_coupon_id, 'wc_sc_max_discount', $wc_sc_max_discount, true, $order );
}
if ( $this->is_wc_gte_32() ) {
$wc_sc_expiry_time = ( true === $is_callable_coupon_get_meta ) ? (int) $coupon->get_meta( 'wc_sc_expiry_time' ) : (int) get_post_meta( $coupon_id, 'wc_sc_expiry_time', true );
if ( ! empty( $wc_sc_expiry_time ) ) {
if ( true === $is_callable_smart_coupon_update_meta ) {
$smart_coupon->update_meta_data( 'wc_sc_expiry_time', $wc_sc_expiry_time );
} else {
update_post_meta( $smart_coupon_id, 'wc_sc_expiry_time', $wc_sc_expiry_time );
}
}
}
if ( $this->is_callable( $smart_coupon, 'save' ) ) {
$smart_coupon->save();
}
/**
* Hook for 3rd party developers to add data in generated coupon
*
* New coupon id new_coupon_id Newly generated coupon post id
* Reference coupon ref_coupon This is the coupon from which meta will be copied to newly created coupon
*/
do_action(
'wc_sc_new_coupon_generated',
array(
'new_coupon_id' => $smart_coupon_id,
'ref_coupon' => $coupon,
)
);
$generated_coupon_details = array(
'parent' => ( ! empty( $coupon_id ) ) ? $coupon_id : 0,
'code' => $smart_coupon_code,
'amount' => $amount,
);
$smart_coupon_codes[ $email_id ][] = $generated_coupon_details;
if ( ! empty( $order_id ) ) {
$is_gift = ( true === $is_callable_order_get_meta ) ? $order->get_meta( 'is_gift' ) : get_post_meta( $order_id, 'is_gift', true );
} else {
$is_gift = 'no';
}
if ( is_array( $email ) && ! empty( $coupon_id ) && isset( $email[ $coupon_id ] ) ) {
$message_index = array_search( $email_id, $email[ $coupon_id ], true );
if ( false !== $message_index && isset( $receivers_messages[ $coupon_id ][ $message_index ] ) && ! empty( $receivers_messages[ $coupon_id ][ $message_index ] ) ) {
$message_from_sender = $receivers_messages[ $coupon_id ][ $message_index ];
unset( $email[ $coupon_id ][ $message_index ] );
$this->update_post_meta( $order_id, 'temp_gift_card_receivers_emails', $email, false, $order );
}
}
if ( ( isset( $schedule_gift_sending ) && 'yes' === $schedule_gift_sending && $this->is_valid_timestamp( $sending_timestamp ) ) ) {
$wc_sc_coupon_receiver_details = array(
'coupon_details' => $generated_coupon_details,
'gift_certificate_receiver_email' => $email_id,
'gift_certificate_receiver_name' => $gift_certificate_receiver_name,
'message_from_sender' => $message_from_sender,
'gift_certificate_sender_name' => $gift_certificate_sender_name,
'gift_certificate_sender_email' => $gift_certificate_sender_email,
);
if ( true === $is_callable_smart_coupon_update_meta ) {
$smart_coupon->update_meta_data( 'wc_sc_coupon_receiver_details', $wc_sc_coupon_receiver_details );
} else {
update_post_meta( $smart_coupon_id, 'wc_sc_coupon_receiver_details', $wc_sc_coupon_receiver_details );
}
} else {
$is_send_email = $this->is_email_template_enabled();
$combine_emails = $this->is_email_template_enabled( 'combine' );
if ( 'yes' === $is_send_email ) {
if ( 'yes' === $combine_emails ) {
$coupon_receiver_details = ( true === $is_callable_order_get_meta ) ? $order->get_meta( 'sc_coupon_receiver_details' ) : get_post_meta( $order_id, 'sc_coupon_receiver_details', true );
if ( empty( $coupon_receiver_details ) || ! is_array( $coupon_receiver_details ) ) {
$coupon_receiver_details = array();
}
$coupon_receiver_details[] = array(
'code' => $generated_coupon_details['code'],
'amount' => $amount,
'email' => $email_id,
'message' => $message_from_sender,
);
$this->update_post_meta( $order_id, 'sc_coupon_receiver_details', $coupon_receiver_details, false, $order );
} else {
$this->sa_email_coupon( array( $email_id => $generated_coupon_details ), $type, $order_id, $gift_certificate_receiver_name, $message_from_sender, $gift_certificate_sender_name, $gift_certificate_sender_email, $is_gift );
}
} else {
if ( ! empty( $order_id ) ) {
$coupon_receiver_details = ( true === $is_callable_order_get_meta ) ? $order->get_meta( 'sc_coupon_receiver_details' ) : get_post_meta( $order_id, 'sc_coupon_receiver_details', true );
if ( empty( $coupon_receiver_details ) || ! is_array( $coupon_receiver_details ) ) {
$coupon_receiver_details = array();
}
$coupon_receiver_details[] = array(
'code' => $generated_coupon_details['code'],
'amount' => $amount,
'email' => $email_id,
'message' => $message_from_sender,
);
$this->update_post_meta( $order_id, 'sc_coupon_receiver_details', $coupon_receiver_details, false, $order );
}
}
}
if ( $this->is_callable( $smart_coupon, 'save' ) ) {
$smart_coupon->save();
}
}
return $smart_coupon_codes;
}
/**
* Function to set that Smart Coupons plugin is used to auto generate a coupon
*
* @param array $args Data.
*/
public function smart_coupons_plugin_used( $args = array() ) {
$is_show_review_notice = get_option( 'wc_sc_is_show_review_notice' );
if ( false === $is_show_review_notice ) {
update_option( 'wc_sc_is_show_review_notice', time(), 'no' );
}
}
/**
* Add button to export coupons on Coupons admin page
*/
public function woocommerce_restrict_manage_smart_coupons() {
global $typenow, $wp_query, $wp, $woocommerce_smart_coupon;
if ( 'shop_coupon' !== $typenow ) {
return;
}
$is_print = get_option( 'smart_coupons_is_print_coupon', 'yes' );
$is_print = apply_filters( 'wc_sc_admin_show_print_button', wc_string_to_bool( $is_print ), array( 'source' => $woocommerce_smart_coupon ) );
$print_url = add_query_arg(
array(
'print-coupons' => 'yes',
'source' => 'wc-smart-coupons',
'coupon-codes' => '',
),
home_url()
);
wc_product_dropdown_categories(
array(
'selected' => isset( $wp_query->query_vars['sc_coupon_category'] ) ? $wp_query->query_vars['sc_coupon_category'] : '',
'taxonomy' => 'sc_coupon_category',
'name' => 'sc_coupon_category',
'option_select_text' => __( 'Filter by category', 'woocommerce-smart-coupons' ),
'hide_empty' => 0,
)
);
?>
' . $file . '' ) . ' ' . __FILE__ . ' ' . __LINE__ );
}
} else {
$file = trailingslashit( WP_PLUGIN_DIR . '/' . WC_SC_PLUGIN_DIRNAME ) . 'assets/css/smart-coupon-designs.css';
if ( file_exists( $file ) ) {
include $file;
} else {
/* translators: File path */
$this->log( 'error', sprintf( __( 'File not found %s', 'woocommerce-smart-coupons' ), '' . $file . '' ) . ' ' . __FILE__ . ' ' . __LINE__ );
}
}
$styles = ob_get_clean();
if ( 'yes' === $is_email ) {
$styles = str_replace( array( ':before', ':hover', ':focus', ':active' ), array( '-pseudo-before', '-pseudo-hover', '-pseudo-focus', '-pseudo-active' ), $styles );
}
return apply_filters( 'wc_sc_get_coupon_styles', $styles, $style_name, $args );
}
/**
* Insert a setting or an array of settings after another specific setting by its ID.
*
* @since 1.2.1
* @param array $settings The original list of settings.
* @param string $insert_after_setting_id The setting id to insert the new setting after.
* @param array $new_setting The new setting to insert. Can be a single setting or an array of settings.
* @param string $insert_type The type of insert to perform. Can be 'single_setting' or 'multiple_settings'. Optional. Defaults to a single setting insert.
*
* @credit: WooCommerce Subscriptions
*/
public static function insert_setting_after( &$settings, $insert_after_setting_id, $new_setting, $insert_type = 'single_setting' ) {
if ( ! is_array( $settings ) ) {
return;
}
$original_settings = $settings;
$settings = array();
foreach ( $original_settings as $setting ) {
$settings[] = $setting;
if ( isset( $setting['id'] ) && $insert_after_setting_id === $setting['id'] ) {
if ( 'single_setting' === $insert_type ) {
$settings[] = $new_setting;
} else {
$settings = array_merge( $settings, $new_setting );
}
}
}
}
/**
* To generate unique id
*
* Credit: WooCommerce
*/
public function generate_unique_id() {
require_once ABSPATH . 'wp-includes/class-phpass.php';
$hasher = new PasswordHash( 8, false );
return md5( $hasher->get_random_bytes( 32 ) );
}
/**
* To get cookie life
*/
public function get_cookie_life() {
$life = get_option( 'wc_sc_coupon_cookie_life', 180 );
return apply_filters( 'wc_sc_coupon_cookie_life', time() + ( 60 * 60 * 24 * $life ) );
}
/**
* Show notice on admin panel about minimum required version of WooCommerce
*/
public function minimum_woocommerce_version_requirement() {
if ( $this->is_wc_gte_30() ) {
return;
}
$plugin_data = self::get_smart_coupons_plugin_data();
$plugin_name = $plugin_data['Name'];
?>
' . esc_html__( 'Important', 'woocommerce-smart-coupons' ) . ': ' . esc_html( $plugin_name ) . ' ' . esc_html__( 'is active but it will only work with WooCommerce 3.0.0+.', 'woocommerce-smart-coupons' ) . ' ' . esc_html__( 'Please update WooCommerce to the latest version', 'woocommerce-smart-coupons' ) . '.'; ?>
' . $wc_sc_dashboard_endpoint . '',
__( 'Block-enabled Cart', 'woocommerce-smart-coupons' ) => $this->iconify( $is_block_enabled_cart ),
__( 'Block-enabled Checkout', 'woocommerce-smart-coupons' ) => $this->iconify( $is_block_enabled_checkout ),
__( 'WooCommerce Account Connected', 'woocommerce-smart-coupons' ) => $this->iconify( $woocommerce_account_connected ),
);
?>
| : | ||
* * @param string $string The string to be checked. * @param mixed $encodings List of encoding. * @param boolean $strict Strict checking or not. * @return mixed */ public function mb_detect_encoding( $string, $encodings = null, $strict = false ) { if ( function_exists( 'mb_detect_encoding' ) ) { return mb_detect_encoding( $string, $encodings, $strict ); } if ( null === $encodings ) { $encodings = array( 'ASCII', 'UTF-8' ); } else { if ( ! is_array( $encodings ) ) { $encodings = array_map( 'trim', explode( ',', $encodings ) ); } $encodings = array_map( 'strtoupper', $encodings ); } foreach ( $encodings as $enc ) { switch ( $enc ) { case 'ASCII': if ( ! preg_match( '/[\x80-\xFF]/', $string ) ) { return $enc; } break; case 'UTF8': case 'UTF-8': if ( preg_match( '//u', $string ) ) { return 'UTF-8'; } break; default: if ( 0 === strncmp( $enc, 'ISO-8859-', 9 ) ) { return $enc; } } } return false; } /** * Check if a method is callable w.r.t. given object or not * * @param mixed $object The object. * @param string $method The method name. * @return boolean */ public function is_callable( $object = null, $method = '' ) { if ( empty( $object ) || empty( $method ) ) { return false; } $type = gettype( $object ); if ( ! in_array( $type, array( 'string', 'object' ), true ) ) { return false; } if ( 'string' === $type && ! class_exists( $object ) ) { return false; } return is_callable( array( $object, $method ) ); } /** * Wrapper function for checking if a coupon is valid for the cart. * * @param WC_Coupon $coupon The coupon object. * @param WC_Cart|WC_Order $cart_or_order Cart or order object. * @return bool */ public function is_valid( $coupon = null, $cart_or_order = null ) { if ( is_null( $coupon ) ) { return false; } if ( is_null( $cart_or_order ) ) { $cart_or_order = WC()->cart; } $discounts = new WC_Discounts( $cart_or_order ); $valid = $discounts->is_coupon_valid( $coupon ); if ( is_wp_error( $valid ) ) { if ( $this->is_wc_greater_than( '8.8.1' ) && $this->is_callable( $coupon, 'set_error_message' ) && $this->is_callable( $valid, 'get_error_message' ) ) { $coupon->set_error_message( $valid->get_error_message() ); } return false; } return $valid; } /** * Generate link for filter by passed email * * @param string $email The email address. * @return string $link */ public function filter_by_email_link( $email = '' ) { $html = ''; if ( ! empty( $email ) && is_email( $email ) ) { $link = add_query_arg( array( 'post_type' => 'shop_coupon', 'post_status' => 'all', 's' => 'email:' . $email, ), admin_url( 'edit.php' ) ); /* translators: Email address of users */ $html = '' . esc_html( $email ) . ''; } return $html; } /** * Get post by post_title * * @param array $titles The titles to be searched. * @param constant $return_type The return type. * @param array $post_types The post types to be considered for searching. * @return array $posts Found posts */ public function get_post_by_title( $titles = array(), $return_type = OBJECT, $post_types = array() ) { global $wpdb; $query = $wpdb->prepare( "SELECT ID, post_title FROM $wpdb->posts WHERE %d", 1 ); if ( ! is_array( $titles ) ) { $titles = array( $titles ); } $how_many = count( $titles ); $placeholders = array_fill( 0, $how_many, '%s' ); if ( ! empty( $how_many ) ) { if ( $how_many > 1 ) { $query .= $wpdb->prepare( ' AND post_title IN (' . implode( ',', $placeholders ) . ')', // phpcs:ignore $titles ); } else { if ( is_array( $titles ) ) { $titles = current( $titles ); } $query .= $wpdb->prepare( ' AND post_title = %s', $titles ); } } if ( ! is_array( $post_types ) ) { $post_types = array( $post_types ); } $how_many = count( $post_types ); $placeholders = array_fill( 0, $how_many, '%s' ); if ( ! empty( $how_many ) ) { if ( $how_many > 1 ) { $query .= $wpdb->prepare( ' AND post_type IN (' . implode( ',', $placeholders ) . ')', // phpcs:ignore $post_types ); } else { if ( is_array( $post_types ) ) { $post_types = current( $post_types ); } $query .= $wpdb->prepare( ' AND post_type = %s', $post_types ); } } $results = $wpdb->get_results( $query, ARRAY_A ); // phpcs:ignore if ( ! is_wp_error( $results ) && ! empty( $results ) ) { $id_to_post_titles = wp_list_pluck( $results, 'post_title', 'ID' ); $id_to_title_slug = array_map( 'sanitize_title', $id_to_post_titles ); $title_slug_to_id = array_flip( $id_to_title_slug ); $title_slug_to_post = array(); foreach ( $title_slug_to_id as $slug => $id ) { if ( ! empty( $slug ) && ! empty( $id ) ) { $title_slug_to_post[ $slug ] = get_post( $id, $return_type ); } } return $title_slug_to_post; } return null; } /** * Wrapper function to get post type * * @param integer $post_id The post id. * @return string|boolean */ public function get_post_type( $post_id = null ) { if ( ! empty( $post_id ) && $this->is_hpos_order( $post_id ) ) { return 'shop_order'; } return get_post_type( $post_id ); } /** * Function to check whether the order was created prior to version 8.0.0 or not. * * @param WC_Order|int $order The order to be checked. * @return boolean */ public function is_old_sc_order( $order = null ) { if ( empty( $order ) || is_array( $order ) ) { return false; } $orders_prior_to_800 = $this->sc_get_option( 'wc_sc_old_orders_prior_to_800' ); if ( empty( $orders_prior_to_800 ) || 'no' === $orders_prior_to_800 ) { return false; } if ( is_a( $order, 'WC_Order' ) ) { $order_id = $this->is_callable( $order, 'get_id' ) ? $order->get_id() : 0; } else { $order_id = $order; } $order_id = absint( $order_id ); $from_to_groups = array_chunk( $orders_prior_to_800, 2, true ); foreach ( $from_to_groups as $group ) { $group = array_flip( $group ); $from = ( ! empty( $group['from'] ) ) ? absint( $group['from'] ) : 0; $to = ( ! empty( $group['to'] ) ) ? absint( $group['to'] ) : 0; if ( $from <= $to && $order_id >= $from && $order_id <= $to ) { return true; } } return false; } /** * Function to find & record orders that were created when Smart Coupons older than 8.0.0 was active & in which store credit was applied */ public function maybe_sync_orders_prior_to_800() { $orders_prior_to_800 = $this->sc_get_option( 'wc_sc_old_orders_prior_to_800' ); if ( 'no' === $orders_prior_to_800 ) { return; } $args = array( 'return' => 'ids', 'orderby' => 'ID', 'order' => 'ASC', 'limit' => -1, 'smart_coupons_contribution' => array( 'value' => array( '', 'a:0:{}' ), 'compare' => 'NOT IN', ), ); $order_ids = wc_get_orders( $args ); if ( empty( $order_ids ) ) { return; } if ( ! is_array( $orders_prior_to_800 ) || empty( $orders_prior_to_800 ) ) { $orders_prior_to_800 = array(); if ( ! empty( $order_ids ) ) { $from = min( $order_ids ); $to = max( $order_ids ); $orders_prior_to_800[ absint( $from ) ] = 'from'; $orders_prior_to_800[ absint( $to ) ] = 'to'; update_option( 'wc_sc_old_orders_prior_to_800', $orders_prior_to_800, 'no' ); } return; } if ( ! empty( $orders_prior_to_800 ) ) { krsort( $orders_prior_to_800, SORT_NUMERIC ); } $last_800_order = array_search( '8.0.0', $orders_prior_to_800, true ); $last_from_order = array_search( 'from', $orders_prior_to_800, true ); $last_to_order = array_search( 'to', $orders_prior_to_800, true ); $max = max( $last_800_order, $last_from_order, $last_to_order ); if ( ! array_key_exists( $max, $orders_prior_to_800 ) ) { return; } $status = $orders_prior_to_800[ $max ]; $remaining = array_slice( $order_ids, ( array_search( $max, $order_ids, true ) + 1 ) ); if ( empty( $remaining ) ) { return; } switch ( $status ) { case '8.0.0': $from = min( $remaining ); $to = max( $remaining ); $orders_prior_to_800[ absint( $from ) ] = 'from'; $orders_prior_to_800[ absint( $to ) ] = 'to'; break; case 'from': $to = max( $remaining ); $orders_prior_to_800[ absint( $to ) ] = 'to'; break; case 'to': $to = max( $remaining ); unset( $orders_prior_to_800[ $max ] ); $orders_prior_to_800[ absint( $to ) ] = 'to'; break; } $orders_prior_to_800 = array_diff( $orders_prior_to_800, array( '8.0.0' ) ); ksort( $orders_prior_to_800, SORT_NUMERIC ); update_option( 'wc_sc_old_orders_prior_to_800', $orders_prior_to_800, 'no' ); } /** * Function to be executed after the plugin is upgraded. * * @param object $upgrader The upgrader object. * @param array $hook_extra Additional params. */ public function upgrader_process_complete( $upgrader = null, $hook_extra = array() ) { if ( ! empty( $hook_extra['type'] ) && 'plugin' === $hook_extra['type'] && ! empty( $upgrader->result['destination_name'] ) && 'woocommerce-smart-coupons' === $upgrader->result['destination_name'] && isset( $upgrader->new_plugin_data['Woo'] ) && ! empty( $upgrader->new_plugin_data['Woo'] && '18729:05c45f2aa466106a466de4402fff9dde' === $upgrader->new_plugin_data['Woo'] ) ) { if ( $this->is_sc_gte( '8.0.0' ) ) { $this->maybe_sync_orders_prior_to_800(); } else { $this->record_latest_800_order(); } } } /** * Add support for custom meta from Smart Coupons to search for Orders * * @param array $query The query. * @param array $query_vars The query vars. * @return array */ public function custom_meta_support_in_orders_query( $query = array(), $query_vars = array() ) { if ( ! empty( $query_vars['smart_coupons_contribution'] ) ) { $query['meta_query'][] = array( 'key' => 'smart_coupons_contribution', 'value' => array_map( 'esc_attr', $query_vars['smart_coupons_contribution']['value'] ), 'compare' => esc_attr( $query_vars['smart_coupons_contribution']['compare'] ), ); } return $query; } /** * Function to record latest order which was created when Smart Coupons 8.0.0+ was active & store credit was applied to the order. */ public function record_latest_800_order() { $orders_prior_to_800 = $this->sc_get_option( 'wc_sc_old_orders_prior_to_800' ); if ( false !== $orders_prior_to_800 && 'no' !== $orders_prior_to_800 ) { $args = array( 'return' => 'ids', 'orderby' => 'ID', 'order' => 'DESC', 'limit' => 1, 'smart_coupons_contribution' => array( 'value' => array( '', 'a:0:{}' ), 'compare' => 'NOT IN', ), ); if ( function_exists( 'wc_get_orders' ) ) { $order_ids = wc_get_orders( $args ); if ( ! empty( $order_ids ) ) { $last_order_id = current( $order_ids ); if ( ! is_array( $orders_prior_to_800 ) || empty( $orders_prior_to_800 ) ) { $orders_prior_to_800 = array(); } if ( ! array_key_exists( $last_order_id, $orders_prior_to_800 ) ) { $last_array_element = array( absint( $last_order_id ) => '8.0.0' ); $orders_prior_to_800 = $orders_prior_to_800 + $last_array_element; } update_option( 'wc_sc_old_orders_prior_to_800', $orders_prior_to_800, 'no' ); } } } } /** * Format order item meta added by Smart Coupons. * * @param array $formatted_metas Existsing metas. * @param WC_Order_Item $order_item The order item. * @return array */ public function format_sc_meta_data( $formatted_metas = array(), $order_item = null ) { if ( ! empty( $formatted_metas ) ) { $sc_metas_label = array( '_wc_sc_product_source' => __( 'Added by coupon', 'woocommerce-smart-coupons' ), ); foreach ( $formatted_metas as $meta_id => $meta ) { if ( ! empty( $meta->key ) && array_key_exists( $meta->key, $sc_metas_label ) ) { switch ( $meta->key ) { default: $formatted_metas[ $meta_id ]->display_key = $sc_metas_label[ $meta->key ]; break; } } } } return $formatted_metas; } /** * Hide order item metas that are added by the Smart Coupons plugin. * * @param array $metas The existing metas. * @return array */ public function hidden_order_itemmeta( $metas = array() ) { if ( ! is_array( $metas ) || empty( $metas ) ) { $metas = array(); } $sc_metas = array( 'sc_called_credit', 'sc_refunded_discount', 'sc_refunded_discount_tax', 'sc_refunded_user_id', 'sc_refunded_timestamp', 'sc_refunded_coupon_id', 'sc_revoke_refunded_discount', 'sc_revoke_refunded_discount_tax', 'sc_revoke_refunded_user_id', 'sc_revoke_refunded_timestamp', 'sc_revoke_refunded_coupon_id', ); $intersect = array_intersect( $metas, $sc_metas ); if ( count( $sc_metas ) !== count( $intersect ) ) { $metas = array_merge( $metas, $sc_metas ); $metas = array_filter( array_unique( $metas ) ); } return $metas; } /** * Register endpoint data to handle data from Send Coupon Form */ public function register_endpoint_data() { require_once $this->get_plugin_directory( '/blocks/class-wc-sc-extend-store-endpoint.php' ); if ( class_exists( 'Automattic\WooCommerce\StoreApi\StoreApi' ) && $this->is_callable( 'Automattic\WooCommerce\StoreApi\StoreApi', 'container' ) ) { $storeapi_container = Automattic\WooCommerce\StoreApi\StoreApi::container(); if ( $this->is_callable( $storeapi_container, 'get' ) && class_exists( 'Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema' ) ) { $store = $storeapi_container->get( Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema::class ); if ( is_callable( array( $store, 'register_endpoint_data' ) ) && class_exists( 'Automattic\WooCommerce\StoreApi\Schemas\V1\CheckoutSchema' ) ) { $store->register_endpoint_data( array( 'endpoint' => CheckoutSchema::IDENTIFIER, 'namespace' => 'woocommerce-smart-coupons', 'schema_callback' => array( 'WC_SC_Extend_Store_Endpoint', 'extend_checkout_schema' ), 'schema_type' => ARRAY_A, ) ); } } } } /** * Save coupon receiver details that is entered in Send Coupon Form from the Checkout page, in the respective order * * @param \WC_Order $order The order object. * @param \WP_REST_Request $request The REST request object. */ public function save_coupon_receiver_detail_in_order( \WC_Order $order, \WP_REST_Request $request ) { $extensions = $request->get_param( 'extensions' ); $send_coupon_data = ( is_array( $extensions['woocommerce-smart-coupons'] ) && ! empty( $extensions['woocommerce-smart-coupons'] ) ) ? $extensions['woocommerce-smart-coupons'] : array(); $order_billing_email = ( is_a( $order, 'WC_Order' ) && $this->is_callable( $order, 'get_billing_email' ) ) ? $order->get_billing_email() : ''; if ( ! empty( $send_coupon_data['is_gift'] ) ) { $order->update_meta_data( 'is_gift', $send_coupon_data['is_gift'] ); } if ( ! empty( $send_coupon_data['wc_sc_schedule_gift_sending'] ) && 'later' === $send_coupon_data['wc_sc_schedule_gift_sending'] ) { $order->update_meta_data( 'wc_sc_schedule_gift_sending', 'yes' ); } if ( ! empty( $send_coupon_data['send_to'] ) && 'many' === $send_coupon_data['send_to'] ) { if ( isset( $send_coupon_data['gift_receiver_email']['0_0'] ) ) { unset( $send_coupon_data['gift_receiver_email']['0_0'] ); } if ( isset( $send_coupon_data['gift_sending_timestamp']['0_0'] ) ) { unset( $send_coupon_data['gift_sending_timestamp']['0_0'] ); } if ( isset( $send_coupon_data['gift_receiver_message']['0_0'] ) ) { unset( $send_coupon_data['gift_receiver_message']['0_0'] ); } } $send_to_one = ( empty( $send_coupon_data['send_to'] ) || 'many' !== $send_coupon_data['send_to'] ); if ( ! empty( $send_coupon_data['gift_receiver_email'] ) ) { $gift_receiver_email = array(); if ( ! is_scalar( $send_coupon_data['gift_receiver_email'] ) ) { foreach ( $send_coupon_data['gift_receiver_email'] as $key => $email ) { list( $coupon_id, $index ) = explode( '_', $key ); $coupon_id = ( ! empty( $coupon_id ) ) ? intval( $coupon_id ) : 0; $index = ( ! empty( $index ) ) ? intval( $index ) : 0; if ( empty( $gift_receiver_email[ $coupon_id ] ) || ! is_array( $gift_receiver_email[ $coupon_id ] ) ) { $gift_receiver_email[ $coupon_id ] = array(); } if ( true === $send_to_one ) { $gift_receiver_email[ $coupon_id ][ $index ] = ( ! empty( $send_coupon_data['gift_receiver_email']['0_0'] ) ) ? $send_coupon_data['gift_receiver_email']['0_0'] : $order_billing_email; } else { $gift_receiver_email[ $coupon_id ][ $index ] = ( ! empty( $email ) ) ? $email : $order_billing_email; } } } if ( ! empty( $gift_receiver_email ) ) { $order->update_meta_data( 'gift_receiver_email', $gift_receiver_email ); } } if ( ! empty( $send_coupon_data['gift_sending_timestamp'] ) ) { $gift_sending_timestamp = array(); if ( ! is_scalar( $send_coupon_data['gift_sending_timestamp'] ) ) { foreach ( $send_coupon_data['gift_sending_timestamp'] as $key => $timestamp ) { list( $coupon_id, $index ) = explode( '_', $key ); $coupon_id = ( ! empty( $coupon_id ) ) ? intval( $coupon_id ) : 0; $index = ( ! empty( $index ) ) ? intval( $index ) : 0; if ( empty( $gift_sending_timestamp[ $coupon_id ] ) || ! is_array( $gift_sending_timestamp[ $coupon_id ] ) ) { $gift_sending_timestamp[ $coupon_id ] = array(); } if ( true === $send_to_one ) { $gift_sending_timestamp[ $coupon_id ][ $index ] = ( ! empty( $send_coupon_data['gift_sending_timestamp']['0_0'] ) ) ? $send_coupon_data['gift_sending_timestamp']['0_0'] : time(); } else { $gift_sending_timestamp[ $coupon_id ][ $index ] = $timestamp; } } } if ( ! empty( $gift_sending_timestamp ) ) { $order->update_meta_data( 'gift_sending_timestamp', $gift_sending_timestamp ); } } if ( ! empty( $send_coupon_data['gift_receiver_message'] ) ) { $gift_receiver_message = array(); if ( ! is_scalar( $send_coupon_data['gift_receiver_message'] ) ) { foreach ( $send_coupon_data['gift_receiver_message'] as $key => $message ) { list( $coupon_id, $index ) = explode( '_', $key ); $coupon_id = ( ! empty( $coupon_id ) ) ? intval( $coupon_id ) : 0; $index = ( ! empty( $index ) ) ? intval( $index ) : 0; if ( empty( $gift_receiver_message[ $coupon_id ] ) || ! is_array( $gift_receiver_message[ $coupon_id ] ) ) { $gift_receiver_message[ $coupon_id ] = array(); } if ( true === $send_to_one ) { $gift_receiver_message[ $coupon_id ][ $index ] = ( ! empty( $send_coupon_data['gift_receiver_message']['0_0'] ) ) ? $send_coupon_data['gift_receiver_message']['0_0'] : ''; } else { $gift_receiver_message[ $coupon_id ][ $index ] = $message; } } } if ( ! empty( $gift_receiver_message ) ) { $order->update_meta_data( 'gift_receiver_message', $gift_receiver_message ); } } $order->save(); } /** * Check if the order has at least one product that can generate coupon * * @param WC_Order $order The order object. * @return boolean */ public function would_order_generate_coupons( $order = null ) { if ( empty( $order ) ) { return false; } if ( ! is_a( $order, 'WC_Order' ) && is_numeric( $order ) ) { $order = wc_get_order( absint( $order ) ); } $order_items = $this->is_callable( $order, 'get_items' ) ? $order->get_items() : array(); if ( empty( $order_items ) || is_scalar( $order_items ) ) { return false; } foreach ( $order_items as $item ) { if ( $item->is_type( 'line_item' ) ) { $product = $this->is_callable( $item, 'get_product' ) ? $item->get_product() : ( $this->is_callable( $order, 'get_product_from_item' ) ? $order->get_product_from_item( $item ) : null ); if ( ! is_a( $product, 'WC_Product' ) ) { continue; } $linked_coupons = $this->is_callable( $product, 'get_meta' ) ? $product->get_meta( '_coupon_title' ) : array(); if ( empty( $linked_coupons ) && $this->is_callable( $product, 'is_type' ) && true === $product->is_type( 'variation' ) ) { $parent_id = $this->is_callable( $product, 'get_parent_id' ) ? $product->get_parent_id() : 0; if ( ! empty( $parent_id ) ) { $product = wc_get_product( $parent_id ); $linked_coupons = $this->is_callable( $product, 'get_meta' ) ? $product->get_meta( '_coupon_title' ) : array(); } } if ( ! empty( $linked_coupons ) ) { return true; } } } return false; } /** * Resend coupons for an order * * @param integer $order_id The order id. */ public function resend_coupons( $order_id = 0 ) { if ( empty( $order_id ) ) { return; // TODO: Show admin notice that no coupons are generated hence can't send email. } $order = wc_get_order( $order_id ); $is_callable_order_get_meta = is_object( $order ) && $this->is_callable( $order, 'get_meta' ); $sc_coupon_receiver_details = ( true === $is_callable_order_get_meta ) ? $order->get_meta( 'sc_coupon_receiver_details' ) : array(); if ( empty( $sc_coupon_receiver_details ) ) { return; // TODO: Show admin notice that no coupons are generated hence can't send email. } $order_billing_email = ( is_object( $order ) && $this->is_callable( $order, 'get_billing_email' ) ) ? $order->get_billing_email() : ''; $order_billing_first_name = ( is_object( $order ) && $this->is_callable( $order, 'get_billing_first_name' ) ) ? $order->get_billing_first_name() : ''; $order_billing_last_name = ( is_object( $order ) && $this->is_callable( $order, 'get_billing_last_name' ) ) ? $order->get_billing_last_name() : ''; $is_gift = ( true === $is_callable_order_get_meta ) ? $order->get_meta( 'is_gift' ) : ''; $gift_certificate_sender_email = $order_billing_email; $gift_certificate_sender_name = $order_billing_first_name . ' ' . $order_billing_last_name; $coupon_receiver_details = array(); foreach ( $sc_coupon_receiver_details as $detail ) { if ( empty( $detail['email'] ) || empty( $detail['code'] ) ) { continue; } $email = $detail['email']; if ( empty( $coupon_receiver_details[ $email ] ) || ! is_array( $coupon_receiver_details[ $email ] ) ) { $coupon_receiver_details[ $email ] = array(); } $coupon_receiver_details[ $email ][] = $detail; } if ( empty( $coupon_receiver_details ) ) { return; // TODO: Show admin notice that no coupons are generated hence can't send email. } $is_send_email = $this->is_email_template_enabled(); $combine_emails = $this->is_email_template_enabled( 'combine' ); if ( 'yes' === $is_send_email ) { WC()->mailer(); foreach ( $coupon_receiver_details as $receiver_email => $receiver_details ) { if ( 'yes' === $combine_emails ) { if ( count( $receiver_details ) === 1 ) { $coupon_code = ( ! empty( $receiver_details[0]['code'] ) ) ? $receiver_details[0]['code'] : ''; $message_from_sender = ( ! empty( $receiver_details[0]['message'] ) ) ? $receiver_details[0]['message'] : ''; $coupon = new WC_Coupon( $coupon_code ); $coupon_amount = $this->get_amount( $coupon, true, $order ); $discount_type = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_discount_type' ) ) ) ? $coupon->get_discount_type() : ''; $coupon_detail = array( 'amount' => $coupon_amount, 'code' => $coupon_code, ); $action_args = apply_filters( 'wc_sc_email_coupon_notification_args', array( 'order_id' => $order_id, 'email' => $receiver_email, 'coupon' => $coupon_detail, 'discount_type' => $discount_type, 'receiver_name' => '', 'message_from_sender' => $message_from_sender, 'gift_certificate_sender_name' => $gift_certificate_sender_name, 'gift_certificate_sender_email' => $gift_certificate_sender_email, 'is_gift' => $is_gift, ) ); // Trigger single email notification. do_action( 'wc_sc_email_coupon_notification', $action_args ); return; } $action_args = apply_filters( 'wc_sc_email_coupon_notification_args', array( 'order_id' => $order_id, 'email' => $receiver_email, 'receiver_details' => $receiver_details, 'gift_certificate_sender_name' => $gift_certificate_sender_name, 'gift_certificate_sender_email' => $gift_certificate_sender_email, 'is_gift' => $is_gift, ) ); // Trigger combined email notification. do_action( 'wc_sc_combined_email_coupon_notification', $action_args ); } else { foreach ( $receiver_details as $receiver_detail ) { $coupon_code = ( ! empty( $receiver_detail['code'] ) ) ? $receiver_detail['code'] : ''; $message_from_sender = ( ! empty( $receiver_detail['message'] ) ) ? $receiver_detail['message'] : ''; $coupon = new WC_Coupon( $coupon_code ); $coupon_amount = $this->get_amount( $coupon, true, $order ); $discount_type = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_discount_type' ) ) ) ? $coupon->get_discount_type() : ''; $coupon_detail = array( 'amount' => $coupon_amount, 'code' => $coupon_code, ); $action_args = apply_filters( 'wc_sc_email_coupon_notification_args', array( 'order_id' => $order_id, 'email' => $receiver_email, 'coupon' => $coupon_detail, 'discount_type' => $discount_type, 'receiver_name' => '', 'message_from_sender' => $message_from_sender, 'gift_certificate_sender_name' => $gift_certificate_sender_name, 'gift_certificate_sender_email' => $gift_certificate_sender_email, 'is_gift' => $is_gift, ) ); // Trigger single email notification. do_action( 'wc_sc_email_coupon_notification', $action_args ); } } } } } /** * Order action to ignore for email * * @return array */ public function order_actions_to_ignore_for_email() { return apply_filters( 'wc_sc_order_actions_to_ignore_for_email', array( 'woocommerce_order_action_wc_sc_regenerate_coupons', ), array( 'source' => $this ) ); } /** * Get current version of the plugin. * * @return string */ public function get_version() { if ( empty( $this->plugin_data ) ) { $this->plugin_data = self::get_smart_coupons_plugin_data(); } return $this->plugin_data['Version']; } /** * Function to compare with current version of Smart Coupons * * @param string $version Version number to compare. * @return bool */ public function is_sc_gte( $version ) { return version_compare( $this->get_version(), $version, '>=' ); } /** * Get the url of path with respect to plugin. * * @param string $path The path. * @return string */ public function get_plugin_directory_url( $path = '' ) { return plugins_url( $path, WC_SC_PLUGIN_FILE ); } /** * Get the path with respect to plugin. * * @param string $path The path. * @return string */ public function get_plugin_directory( $path = '' ) { return plugin_dir_path( WC_SC_PLUGIN_FILE ) . trim( $path, '/' ); } /** * Function to compare with current version of PHP * * @param string $version Version number to compare. * @return boolean */ public function is_php_gte( $version ) { return version_compare( PHP_VERSION, $version, '>=' ); } /** * Function to check if the passed id is of an order or not * * @param integer $post_id The post id. * @return boolean */ public function is_hpos_order( $post_id = 0 ) { if ( ! empty( $post_id ) && is_numeric( $post_id ) && $this->is_hpos() && $this->is_callable( '\Automattic\WooCommerce\Utilities\OrderUtil', 'is_order' ) ) { return \Automattic\WooCommerce\Utilities\OrderUtil::is_order( $post_id, wc_get_order_types() ); } return false; } /** * Wrapper function to check if HPOS is enabled or not * * @return boolean */ public function is_hpos() { if ( class_exists( '\Automattic\WooCommerce\Utilities\OrderUtil' ) && $this->is_callable( '\Automattic\WooCommerce\Utilities\OrderUtil', 'custom_orders_table_usage_is_enabled' ) ) { return \Automattic\WooCommerce\Utilities\OrderUtil::custom_orders_table_usage_is_enabled(); } return false; } /** * Function to declare WooCommerce HPOS related compatibility status */ public function hpos_compat_declaration() { if ( class_exists( '\Automattic\WooCommerce\Utilities\FeaturesUtil' ) ) { \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'custom_order_tables', 'woocommerce-smart-coupons/woocommerce-smart-coupons.php', true ); } } /** * Function to declare WooCommerce Blocks related compatibility status */ public function blocks_compat_declaration() { if ( class_exists( '\Automattic\WooCommerce\Utilities\FeaturesUtil' ) ) { \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'cart_checkout_blocks', 'woocommerce-smart-coupons/woocommerce-smart-coupons.php', true ); } } /** * Removes a coupon when the corresponding cart item is removed. * * @param string $removed_cart_item_key The key of the removed cart item. * @param WC_Cart $cart The cart array containing cart item data. * @return void */ public function sc_remove_coupon_with_cart_item( $removed_cart_item_key, $cart ) { if ( is_admin() ) { return; } if ( $removed_cart_item_key && isset( $cart->removed_cart_contents[ $removed_cart_item_key ]['wc_sc_product_source'] ) ) { $coupon_code = $cart->removed_cart_contents[ $removed_cart_item_key ]['wc_sc_product_source']; if ( ! empty( $coupon_code ) && WC()->cart->has_discount( $coupon_code ) ) { WC()->cart->remove_coupon( $coupon_code ); } } } }//end class } // End class exists check