newInstanceWithoutConstructor(); } /** * Class construct. * * @param array $settings widget settings. * @param array $widget widget object. * @since 1.1.0 */ public function __construct( $settings, $widget ) { $this->settings = $settings; $this->widget = $widget; $this->actions(); } /** * Actions. * required actions to apply changes to woocommerce checkout shortcode. * * @return void * @since 1.1.0 */ private function actions() { // Empty cart notice. add_action( 'woocommerce_before_checkout_form_cart_notices', [ $this, 'empty_cart_notice' ] ); // sellkit wrapper for checkout widget. add_action( 'woocommerce_before_checkout_form', [ $this, 'open_multistep_wrap' ] ); add_action( 'woocommerce_after_checkout_form', [ $this, 'close_multistep_wrap' ], 999 ); // Add express section to widget. $this->add_express_checkout(); // Replace Woocommerce templates that require huge changes. add_filter( 'woocommerce_locate_template', [ $this, 'template_replace' ], 1, 3 ); // Remove coupon from it's default location. will add custom coupon form based on design at desired location. remove_action( 'woocommerce_before_checkout_form', 'woocommerce_checkout_coupon_form', 10, 1 ); // Filter all woocommerce field right before printing them in our widget. add_filter( 'woocommerce_checkout_fields', [ $this, 'woocommerce_checkout_fields' ] ); // Hide shipping fields section title. add_filter( 'sellkit-checkout-disable-shipping-fields-title', [ $this, 'check_to_disable_shipping_title' ] ); // Customize shipping fields based on user desire. add_action( 'sellkit_checkout_shipping_fields', [ $this, 'sellkit_checkout_shipping_field' ], 10, 2 ); // Customize billing fields based on user desire. add_action( 'sellkit_checkout_billing_fields', [ $this, 'sellkit_checkout_billing_field' ], 10, 2 ); // Rename Shipping text to Shipping Method. add_filter( 'woocommerce_shipping_package_name', [ $this, 'rename_shipping_text' ] ); // Remove login form from default location. remove_action( 'woocommerce_before_checkout_form', 'woocommerce_checkout_login_form', 10 ); // Append widget settings to checkout form 2 hidden fields form_id post_id. add_action( 'woocommerce_checkout_before_customer_details', [ $this, 'widget_settings' ] ); // Apply custom messages. $this->custom_messages(); // Enable or Disable Sections based on user selection. add_action( 'woocommerce_before_checkout_form', function() { self::enable_disable_sections( $this->settings, [] ); } ); // Inject required scripts for google address autocomplete. add_action( 'sellkit-after-checkout-content', [ $this, 'inject_google_autocomplete' ] ); // Order bump html. add_action( 'woocommerce_before_checkout_form', [ $this, 'order_bump' ] ); // Bundle products. $this->bundled_products(); } /** * Add custom notice if cart is empty. * * @return void * @since 1.1.0 */ public function empty_cart_notice() { global $woocommerce; $count = $woocommerce->cart->get_cart_contents_count(); if ( 0 === $count ) { /* translators: %s: Empty cart message. */ echo sprintf( '
%s
', $this->settings['empty_cart'] ); } } /** * Opens a wrapper around widget checkout form. * * @return void * @since 1.1.0 */ public function open_multistep_wrap() { ?>
'; } /** * Inject express checkout section into the checkout form based on layout. * * @return void * @since 1.1.0 */ private function add_express_checkout() { if ( ! sellkit()->has_pro ) { return; } $show_express = true; // Disable express checkout. if ( 'yes' !== $this->settings['show_express_checkout'] ) { $show_express = false; } $gateways = [ 'Paypal_For_Woocommerce', 'Woo_Payment_Gateway', 'Stripe_For_Woocommerce', 'Klarma_Checkout_Woocommerce', 'Amazon_Pay_Woocommerce', 'Stripe_Woocommerce_Official', ]; foreach ( $gateways as $gateway ) { $class = 'Sellkit\Elementor\Modules\Checkout\Integrations\\' . $gateway; $class = new $class(); $class->run(); } if ( false === $show_express ) { return; } if ( 'one-page' === $this->settings['layout-type'] ) { add_action( 'sellkit_checkout_one_page_express_methods', [ $this, 'express_checkout_html' ] ); return; } add_action( 'sellkit-checkout-step-a-begins', [ $this, 'express_checkout_html' ], 20 ); } /** * Replace Woocommerce templates that needs to be changed, locally. * this template_replace does not affect default checkout page. * * @param string $template template name. * @param string $template_name name. * @param string $template_path path of template. * @return string * @since 1.1.0 */ public function template_replace( $template, $template_name, $template_path ) { $basename = basename( $template ); $our_path = sellkit()->plugin_dir() . 'includes/elementor/modules/checkout/'; switch ( $basename ) { case 'form-checkout.php': $template = $our_path . 'templates/form-checkout.php'; break; case 'form-login.php': $template = $our_path . 'templates/form-login.php'; break; case 'form-shipping.php': $template = $our_path . 'templates/form-shipping.php'; break; case 'form-billing.php': $template = $our_path . 'templates/form-billing.php'; break; case 'payment.php': $template = $our_path . 'templates/payment.php'; break; case 'payment-method.php': $template = $our_path . 'templates/payment-method.php'; break; case 'review-order.php': $template = $our_path . 'templates/review-order.php'; break; case 'cart-shipping.php': $template = $our_path . 'templates/cart-shipping.php'; break; case 'cart-item-data.php': $template = $our_path . 'templates/cart-item-data.php'; break; } return $template; } /** * Customize shipping fields parameters based on user needs through widget options. * * @param array $default_fields woocommerce fields. * @return array * @since 1.1.0 */ public function customize_shipping_field( $default_fields ) { $widget_shipping_fields = $this->settings['shipping_list']; $widget_field_slug = Helper::instance()->get_user_defined_fields_slug( $widget_shipping_fields, 'shipping_list_field' ); // Unset default fields. foreach ( $default_fields as $key => $field ) { if ( ! in_array( $key, $widget_field_slug, true ) ) { unset( $default_fields[ $key ] ); } } return $default_fields; } /** * Check to disable shipping fields section title. * * @since 1.2.1 */ public function check_to_disable_shipping_title() { $widget_shipping_fields = $this->settings['shipping_list']; if ( 0 === count( $widget_shipping_fields ) ) { return false; } return true; } /** * Print shipping field in frontend using our customized fields. * * @param array $fields : shipping fields. * @param object $checkout : checkout object. * @since 1.1.0 */ public function sellkit_checkout_shipping_field( $fields, $checkout ) { $default_text = [ 'shipping_first_name', 'shipping_last_name', 'shipping_company', 'shipping_address_1', 'shipping_address_2', 'shipping_postcode', 'shipping_city', ]; $default_select = [ 'shipping_country', 'shipping_state', ]; foreach ( $fields as $key => $details ) { if ( in_array( $key, $default_text, true ) ) { $fields[ $key ]['type'] = 'text'; } if ( in_array( $key, $default_select, true ) ) { $fields[ $key ]['type'] = 'select'; } } $widget_shipping_fields = $this->settings['shipping_list']; $default_fields = Helper::instance()->assign_settings_per_field( $fields, $widget_shipping_fields, 'shipping', $this->settings ); $priority = array_column( $default_fields, 'priority' ); array_multisort( $priority, SORT_ASC, $default_fields ); foreach ( $default_fields as $key => $details ) { if ( ! array_key_exists( 'type', $details ) ) { continue; } $class = $details['type']; $class = '\Sellkit\Elementor\Modules\Checkout\Fields\\' . ucfirst( $class ); $class = new $class(); $field = ''; $class->final_html_structure( $field, $details, $key ); } } /** * Customize billing fields parameters based on user needs through widget options. * * @param array $default_fields woocommerce fields. * @return array * @since 1.1.0 */ public function customize_billing_field( $default_fields ) { $widget_billing_fields = $this->settings['billing_list']; $widget_field_slug = Helper::instance()->get_user_defined_fields_slug( $widget_billing_fields, 'billing_list_field' ); // Unset default fields. foreach ( $default_fields as $key => $field ) { if ( ! in_array( $key, $widget_field_slug, true ) && 'billing_email' !== $field ) { unset( $default_fields[ $key ] ); } } return $default_fields; } /** * Print billing fields in frontend using our customized fields. * * @param array $fields : billing fields. * @param object $checkout : checkout object. * @since 1.1.0 */ public function sellkit_checkout_billing_field( $fields, $checkout ) { $default_text = [ 'billing_first_name', 'billing_last_name', 'billing_company', 'billing_address_1', 'billing_address_2', 'billing_postcode', 'billing_city', ]; $default_select = [ 'billing_country', 'billing_state', ]; $default_tel = [ 'billing_phone', ]; foreach ( $fields as $key => $details ) { if ( in_array( $key, $default_text, true ) ) { $fields[ $key ]['type'] = 'text'; } if ( in_array( $key, $default_select, true ) ) { $fields[ $key ]['type'] = 'select'; } if ( in_array( $key, $default_tel, true ) ) { $fields[ $key ]['type'] = 'tel'; } } $widget_billing_fields = $this->settings['billing_list']; $default_fields = Helper::instance()->assign_settings_per_field( $fields, $widget_billing_fields, 'billing', $this->settings ); $priority = array_column( $default_fields, 'priority' ); array_multisort( $priority, SORT_ASC, $default_fields ); foreach ( $default_fields as $key => $details ) { // Never shot field that it's type is not defined. if ( ! array_key_exists( 'type', $details ) ) { continue; } // Billing email is already defined at top of page. if ( 'billing_email' === $key ) { continue; } $class = $details['type']; $class = '\Sellkit\Elementor\Modules\Checkout\Fields\\' . ucfirst( $class ); $class = new $class(); $field = ''; $field = $class->final_html_structure( $field, $details, $key ); } } /** * Hook to fields before shortcode. * * @param array $default_fields woocommerce fields. * @return array * @since 1.1.0 */ public function woocommerce_checkout_fields( $default_fields ) { $widget_billing_fields = $this->settings['billing_list']; $widget_shipping_fields = $this->settings['shipping_list']; // Unset fields. $default_shipping_fields = $default_fields['shipping']; $default_fields['shipping'] = $this->customize_shipping_field( $default_shipping_fields ); // Unset fields. $default_billing_fields = $default_fields['billing']; $default_fields['billing'] = $this->customize_billing_field( $default_billing_fields ); foreach ( $widget_billing_fields as $data ) { $slug = $data['billing_list_field']; if ( 'yes' !== $data['billing_list_required'] && array_key_exists( $slug, $default_fields['billing'] ) ) { $default_fields['billing'][ $slug ]['required'] = false; unset( $default_fields['billing'][ $slug ]['required'] ); } } foreach ( $widget_shipping_fields as $data ) { $slug = $data['shipping_list_field']; if ( 'yes' !== $data['shipping_list_required'] && array_key_exists( $slug, $default_fields['shipping'] ) ) { $default_fields['shipping'][ $slug ]['required'] = false; unset( $default_fields['shipping'][ $slug ]['required'] ); } } return $default_fields; } /** * Rename Shipping text * * @param string $name title of shipping methods. * @return string * @since 1.1.0 */ public function rename_shipping_text( $name ) { return '

' . __( 'Shipping Methods', 'sellkit' ) . '

'; } /** * Adds widget settings as hidden input to checkout form, to be used in various places. * * @return void * @since 1.1.0 */ public function widget_settings() { ?> documents ) && ! empty( Elementor::$instance->documents->get_current() ) ) { return Elementor::$instance->documents->get_current()->get_main_id(); } return get_the_ID(); } /** * Express checkout html. * * @return void * @since 1.1.0 */ public function express_checkout_html() { ob_start(); ?>
settings['already_have_account_text']; } ); add_filter( 'sellkit_core/widgets/checkout/custom_message/login_toggle_text', function() { return $this->settings['login_toggle_text']; } ); add_action( 'sellkit_core/widgets/checkout/custom_message/create_website_account', function() { $site = get_bloginfo( 'name' ); $text = $this->settings['create_website_account']; echo str_replace( '{{website}}', $site, $text ); } ); add_filter( 'sellkit_core/widgets/checkout/custom_message/secure_transaction_text', function() { return $this->settings['secure_transaction_text']; } ); add_filter( 'sellkit_core/widgets/checkout/custom_message/select_address_text', function() { return $this->settings['select_address_text']; } ); add_filter( 'sellkit-checkout-place-order-btn-text', function( $default ) { if ( ! empty( $this->settings['place_order_btn_txt'] ) ) { return $this->settings['place_order_btn_txt']; } return $default; }, 10 ); } /** * Enable or disable some of checkout sections. * * @param array $settings widget settings. * @param array $posted_data checkout form data. * @return void * @since 1.1.0 */ public static function enable_disable_sections( $settings, $posted_data = [] ) { if ( Elementor::$instance->editor->is_edit_mode() || array_key_exists( 'sellkit-elementor-editor-mode', $posted_data ) ) { add_action( 'sellkit-checkout-after-coupon-form-ajax', [ Helper::instance(), 'editor_mode_extra_js' ] ); // Let coupon form to be viewable in editor mode. add_action( 'sellkit-checkout-widget-custom-coupon-form', function() use ( $settings ) { Global_Hooks::instance()->coupon_form( $settings ); } ); return; } if ( wp_doing_ajax() ) { // Hide order item images. add_filter( 'sellkit/includes/elementor/modules/checkout/product-image', function( $img_html ) use ( $settings ) { if ( ! array_key_exists( 'order_summary_show_image', $settings ) ) { return $img_html; } return ''; } ); add_filter( 'sellkit-checkout-cart-item', function( $cart_item ) use ( $settings ) { if ( ! array_key_exists( 'show_cart_items', $settings ) ) { return $cart_item; } return ''; } ); // Disable order item quantity input. if ( array_key_exists( 'show_cart_edit', $settings ) || array_key_exists( 'bundle-products-force', $posted_data ) ) { add_action( 'sellkit-checkout-widget-disable-quantity', [ Helper::instance(), 'checkout_order_hidden_quantity' ], 10, 2 ); } add_filter( 'woocommerce_shipping_package_name', function() { return '

' . esc_html__( 'Shipping Methods', 'sellkit' ) . '

'; } ); add_filter( 'woocommerce_cart_ready_to_calc_shipping', function() use ( $settings ) { if ( ! array_key_exists( 'show_shipping_method', $settings ) ) { return true; } return false; } ); add_action( 'sellkit-checkout-widget-custom-coupon-form', function() use ( $settings ) { Global_Hooks::instance()->coupon_form( $settings ); } ); return; } // Normal mode when page is loading. add_filter( 'woocommerce_cart_ready_to_calc_shipping', function() use ( $settings ) { if ( 'yes' === $settings['show_shipping_method'] ) { return true; } return false; }, 10 ); add_filter( 'sellkit/includes/elementor/modules/checkout/product-image', function( $img_html ) use ( $settings ) { if ( 'yes' === $settings['order_summary_show_image'] ) { return $img_html; } return ''; } ); add_filter( 'sellkit-checkout-cart-item', function( $cart_item ) use ( $settings ) { if ( 'yes' === $settings['show_cart_items'] ) { return $cart_item; } return ''; }, 10 ); // Disable order item quantity input. if ( array_key_exists( 'show_cart_edit', $settings ) ) { add_action( 'sellkit-checkout-widget-disable-quantity', [ Helper::instance(), 'checkout_order_hidden_quantity' ], 10, 2 ); add_filter( 'sellkit/includes/elementor/modules/checkout/quanity/class', function( $classes ) { return $classes .= ' sellkit-checkout-widget-d-block'; } ); } add_filter( 'sellkit-checkout-place-order-btn-text', function( $place_order_btn ) { if ( ! empty( $settings['place_order_btn_txt'] ) ) { return $settings['place_order_btn_txt']; } return $place_order_btn; }, 10 ); add_action( 'sellkit-checkout-widget-custom-coupon-form', function() use ( $settings ) { if ( 'yes' !== $settings['show_coupon_field'] ) { return; } self::coupon_form( $settings ); } ); } /** * Inject google autocomplete address script if enabled for shipping/billing section. * * @return void * @since 1.1.0 */ public function inject_google_autocomplete() { if ( ! sellkit()->has_pro ) { return; } \Sellkit_Elementor_Checkout_Pro_Module::checkout_google_autocomplete_address( $this->settings ); } /** * Place custom coupon form in checkout order-review based design. * ! we have used same form in Global_Hooks. but this one for first load of page. * * @param array $settings widget settings. * @see sellkit_Core\Raven\Modules\Checkout\Classes\Global_Hooks::coupon_form. * @return void * @since 1.1.0 */ public static function coupon_form( $settings ) { echo ''; self::form( $settings ); echo ''; } /** * New custom coupon form HTML. * * @param array $settings widget settings. * @return void * @since 1.1.0 */ public static function form( $settings ) { $class = 'sellkit-custom-coupon-form-d-none'; if ( ! array_key_exists( 'coupon_field_type', $settings ) || 'normal' === $settings['coupon_field_type'] ) { $class = 'sellkit-normal-coupon-form'; } ?> editor_mode_extra_js(); ?>

query_vars; $option = 'allow-buyers'; if ( array_key_exists( 'funnel_product_settings', $query ) ) { $option = $query['funnel_product_settings']; } if ( 'allow-buyers' === $option ) { return; } add_action( 'sellkit_checkout_required_hidden_fields', function() use ( $option ) { ?> cart->get_cart(); $default = null; $default_q = null; ob_start(); ?>
$cart_item ) : ?> get_id(); $default_q = $cart_item['quantity']; $unique_id = 'bundle-unique-id-' . $default; ?>
cart->get_product_subtotal( $_product, $cart_item['quantity'] ), $cart_item, $cart_item_key ); ?>

cart->empty_cart(); if ( null !== $default ) { WC()->cart->add_to_cart( $default, $default_q ); } } } /** * Trigger to activate order bumb or not for this checkout. * * @param array $data checkout form data. * @since 1.1.0 * @return void */ public static function order_bump( $data = [] ) { if ( 'woocommerce_before_checkout_form' === current_action() ) { self::order_bump_frontend_manager(); return; } if ( ! array_key_exists( 'sellkit_current_page_id', $data ) ) { return; } $bumps_in_cart = []; $simple_bumps = []; $page = $data['sellkit_current_page_id']; $funnel = new Sellkit_Funnel( $page ); if ( ! array_key_exists( 'bump', $funnel->current_step_data ) ) { return; } $bumps = $funnel->current_step_data['bump']; // Get added bump products in cart. foreach ( $data as $key => $value ) { if ( strpos( $key, 'sellkit_bump_data' ) !== false ) { $bumps_in_cart[] = $value; } } if ( empty( $bumps_in_cart ) ) { return; } foreach ( $bumps as $bump ) { // Check if product is set for bump. if ( ! array_key_exists( 'products', $bump['data'] ) ) { continue; } $products = $bump['data']['products']; $product_id = array_key_first( $products['list'] ); $product_details = current( $products['list'] ); // Check if product has discount. if ( empty( $product_details['discount'] ) ) { continue; } $simple_bumps[ $product_id ] = [ 'type' => $product_details['discountType'], 'discount' => $product_details['discount'], ]; } if ( empty( $simple_bumps ) ) { return; } $fee = 0; foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) { $product_id = apply_filters( 'woocommerce_cart_item_product_id', $cart_item['product_id'], $cart_item, $cart_item_key ); if ( ! array_key_exists( $product_id, $simple_bumps ) ) { continue; } $discount_data = $simple_bumps[ $product_id ]; $quantity = $cart_item['quantity']; $price = $cart_item['data']->get_price(); $total = $price * $quantity; if ( 'percentage' === $discount_data['type'] ) { $discount = ( $total * $discount_data['discount'] ) / 100; } else { $discount = $discount_data['discount']; } $fee = $fee + $discount; } if ( $fee <= 0 ) { return; } add_action( 'woocommerce_cart_calculate_fees', function() use ( $fee ) { WC()->cart->add_fee( esc_html__( 'Bump Discount', 'sellkit' ), -$fee, true, 'standard' ); } ); } /** * Order bump to manage frontend. * * @since 1.1.0 * @return void */ private static function order_bump_frontend_manager() { global $wp_query; $query = $wp_query->query_vars; if ( ! array_key_exists( 'bump_data', $query ) ) { return; } $bumps = $query['bump_data']; foreach ( $bumps as $bump ) { if ( ! array_key_exists( 'products', $bump['data'] ) ) { continue; } $design = $bump['data']['design']; $products = $bump['data']['products']; add_action( $design['sellkit_funnels_bump_position'], function() use ( $design, $products ) { self::bump_html( $design, $products ); }, 5 ); } } /** * Order bump html. * * @param array $design design properties. * @param array $products products details. * @since 1.1.0 * @return void */ public static function bump_html( $design, $products ) { $list = $products['list']; $ids = []; foreach ( $list as $id => $details ) { $ids[] = $id; $qty = $details['quantity']; $discount = $details['discount']; $type = $details['discountType']; } $ids_string = implode( '|', $ids ); $product = wc_get_product( $ids_string ); $qty = ( empty( $qty ) ) ? 1 : $qty; if ( empty( $product ) || ! $product->get_id() ) { return; } $unique_id = 'bump-title-' . $ids_string; $class = ''; if ( 'sellkit-checkout-before-order-summary' === current_action() || 'sellkit-checkout-after-order-summary' === current_action() ) { $class = 'sellkit-bump-review-order'; } ?>
get_price(); $discount_value = $discount; if ( 'percentage' === $type ) { $discount_value = ( $real_price * $discount ) / 100; } $discount_price = $real_price - $discount_value; ?> get_price() ); ?>