HEX
Server: LiteSpeed
System: Linux server902.web-hosting.com 4.18.0-553.54.1.lve.el8.x86_64 #1 SMP Wed Jun 4 13:01:13 UTC 2025 x86_64
User: deshuvsd (2181)
PHP: 8.1.33
Disabled: NONE
Upload Files
File: /home/deshuvsd/www/wp-content/plugins/cartflows-pro/classes/class-cartflows-pro-flow-frontend.php
<?php
/**
 * Frontend & Markup
 *
 * @package cartflows
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

/**
 * Flow Markup
 *
 * @since 1.0.0
 */
class Cartflows_Pro_Flow_Frontend {


	/**
	 * Member Variable
	 *
	 * @var object instance
	 */
	private static $instance;

	/**
	 *  Initiator
	 */
	public static function get_instance() {
		if ( ! isset( self::$instance ) ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	/**
	 *  Constructor
	 */
	public function __construct() {

		if ( _is_cartflows_pluspro() ) {
			/* Analytics */
			add_action( 'wp_footer', array( $this, 'footer_markup' ) );
		}
	}

	/**
	 *  Footer markup
	 */
	public function footer_markup() {

		if ( _is_wcf_base_offer_type() ) {

			$open_class = '';

			// Reason for PHPCS ignore: This is used only to check the gateway has sent any response or not and used to print the HTML in the footer on WP action.
			if ( isset( $_GET['wcf-mollie-return'] ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended
				$open_class = ' show ';
			}

			global $post;
			$process_order_text = wcf_pro()->options->get_offers_meta_value( $post->ID, 'wcf-offer-order-process-text' );
			$offer_success_note = wcf_pro()->options->get_offers_meta_value( $post->ID, 'wcf-offer-order-success-note' );
			// @codingStandardsIgnoreStart
			?>
			<div class="wcf-loader-bg <?php echo $open_class; ?>">
				<div class="wcf-loader-wrap">
					<div class="wcf-loader"><?php _e( 'Loading...', 'cartflows-pro' ); ?></div>
					<div class="wcf-order-msg">
						<p class="wcf-process-msg" ><?php echo esc_html( $process_order_text ) ?></p>
						<p class="wcf-note wcf-note-yes"><?php echo esc_html( $offer_success_note ); ?></p>
						<p class="wcf-note wcf-note-no"><?php _e( 'Please wait while we redirect you...', 'cartflows-pro' ); ?></p>
					</div>
				</div>
			</div>
			<?php
			// @codingStandardsIgnoreEnd
		}
	}

	/**
	 * Get next step URL.
	 *
	 * @since 1.0.0
	 * @param int   $step_id step ID.
	 * @param array $data order data.
	 *
	 * @return string
	 */
	public function get_next_step_url( $step_id, $data ) {

		$wcf_step_obj  = wcf_pro_get_step( $step_id );
		$step_id       = intval( $step_id );
		$flow_id       = $wcf_step_obj->get_flow_id();
		$flow_steps    = $wcf_step_obj->get_flow_steps();
		$control_step  = $wcf_step_obj->get_control_step();
		$link          = '#';
		$next_step_id  = false;
		$order_id      = $data['order_id'];
		$order_key     = $data['order_key'];
		$template_type = isset( $data['template_type'] ) ? $data['template_type'] : '';
		$session_key   = wcf_pro()->session->get_session_key( $flow_id );

		if ( ! $flow_id ) {
			return $link;
		}

		if ( 'upsell' === $template_type ) {

			if ( 'offer_accepted' === $data['action'] ) {
				$next_step_id = $this->get_next_step_id_for_upsell_accepted( $wcf_step_obj, $flow_steps, $step_id, $control_step );
			} else {
				$next_step_id = $this->get_next_step_id_for_upsell_rejected( $wcf_step_obj, $flow_steps, $step_id, $control_step );
			}
		} elseif ( 'downsell' === $template_type ) {

			if ( 'offer_accepted' === $data['action'] ) {
				$next_step_id = $this->get_next_step_id_for_downsell_accepted( $wcf_step_obj, $flow_steps, $step_id, $control_step );
			} else {
				$next_step_id = $this->get_next_step_id_for_downsell_rejected( $wcf_step_obj, $flow_steps, $step_id, $control_step );
			}
		} else {

			/* This is normal next step of flow */
			$next_step_id = $wcf_step_obj->get_next_step_id();
		}

		$order = wc_get_order( $order_id );

		if ( $order ) {
			$next_step_id = Cartflows_Pro_Base_Offer_Markup::get_instance()->maybe_skip_offer( $next_step_id, $order );
		}

		if ( $next_step_id ) {

			$this->may_be_complete_order( $next_step_id, $order_id );

			$query_args = array(
				'wcf-order' => $order_id,
				'wcf-key'   => $order_key,
			);

			if ( $session_key ) {
				$query_args['wcf-sk'] = $session_key;
			}

			// Add extra query strings of URL to the next step URL, if exists.
			$query_args = wcf_pro()->utils->may_be_append_query_string( $query_args );

			$link = add_query_arg( $query_args, get_permalink( $next_step_id ) );
		}

		return $link;
	}

	/**
	 * Normalize status if template is of type thank you page.
	 *
	 * @since 1.0.0
	 * @param int $next_step_id next step ID.
	 * @param int $order_id order id.
	 *
	 * @return void
	 */
	public function may_be_complete_order( $next_step_id, $order_id ) {

		wcf()->logger->log( 'Entering: ' . __CLASS__ . '::' . __FUNCTION__ );

		$template_type = get_post_meta( $next_step_id, 'wcf-step-type', true );

		if ( 'thankyou' === $template_type ) {

			$order = wc_get_order( $order_id );

			wcf_pro()->order->may_be_normalize_status( $order );
		}
	}

	/**
	 * Get next step id for upsell.
	 *
	 * @since 1.0.0
	 * @param object $wcf_step_obj step object.
	 * @param array  $steps        flow steps.
	 * @param int    $step_id      step ID.
	 * @param int    $control_step control step ID.
	 *
	 * @return int
	 */
	public function get_next_step_id_for_upsell_accepted( $wcf_step_obj, $steps, $step_id, $control_step ) {

		$next_step_id    = false;
		$next_step_index = false;

		if ( empty( $steps ) ) {
			return $next_step_id;
		} else {
			$next_yes_step = get_post_meta( $step_id, 'wcf-yes-next-step', true );

			if ( ! empty( $next_yes_step ) ) {

				$next_step_id = $next_yes_step;
			} else {

				foreach ( $steps as $i => $step ) {

					if ( intval( $step['id'] ) === $control_step ) {

						$next_step_index = $i + 1;
						break;
					}
				}

				while ( $next_step_index && isset( $steps[ $next_step_index ] ) ) {

					$temp_next_step_id       = $steps[ $next_step_index ]['id'];
					$temp_next_step_template = get_post_meta( $temp_next_step_id, 'wcf-step-type', true );

					if ( 'downsell' === $temp_next_step_template ) {
						$next_step_index++;
					} else {
						$next_step_id = $temp_next_step_id;
						break;
					}
				}
			}
		}

		return $next_step_id;
	}

	/**
	 * Get next step id for upsell rejected.
	 *
	 * @since 1.0.0
	 * @param object $wcf_step_obj step object.
	 * @param array  $steps        flow steps.
	 * @param int    $step_id      step ID.
	 * @param int    $control_step control step ID.
	 *
	 * @return int
	 */
	public function get_next_step_id_for_upsell_rejected( $wcf_step_obj, $steps, $step_id, $control_step ) {

		$next_step_id = false;

		if ( empty( $steps ) ) {
			return $next_step_id;
		} else {

			$next_no_step = get_post_meta( $step_id, 'wcf-no-next-step', true );

			if ( ! empty( $next_no_step ) ) {
				$next_step_id = $next_no_step;
			} else {

				$next_step_id = $wcf_step_obj->get_next_step_id();
			}
		}

		return $next_step_id;
	}

	/**
	 * Get next step id for downsell accepted.
	 *
	 * @since 1.0.0
	 * @param object $wcf_step_obj step object.
	 * @param array  $steps        flow steps.
	 * @param int    $step_id      step ID.
	 * @param int    $control_step control step ID.
	 *
	 * @return int
	 */
	public function get_next_step_id_for_downsell_accepted( $wcf_step_obj, $steps, $step_id, $control_step ) {

		$next_step_id = false;

		if ( empty( $steps ) ) {
			return $next_step_id;
		} else {
			$next_yes_step = get_post_meta( $step_id, 'wcf-yes-next-step', true );

			if ( ! empty( $next_yes_step ) ) {
				$next_step_id = $next_yes_step;
			} else {

				$next_step_id = $wcf_step_obj->get_next_step_id();
			}
		}

		return $next_step_id;
	}

	/**
	 * Get next step id for downsell rejected.
	 *
	 * @since 1.0.0
	 * @param object $wcf_step_obj step object.
	 * @param array  $steps        flow steps.
	 * @param int    $step_id      step ID.
	 * @param int    $control_step control step ID.
	 *
	 * @return int
	 */
	public function get_next_step_id_for_downsell_rejected( $wcf_step_obj, $steps, $step_id, $control_step ) {

		$next_step_id = false;

		if ( empty( $steps ) ) {
			return $next_step_id;
		} else {

			$next_no_step = get_post_meta( $step_id, 'wcf-no-next-step', true );

			if ( ! empty( $next_no_step ) ) {
				$next_step_id = $next_no_step;
			} else {

				$next_step_id = $wcf_step_obj->get_next_step_id();
			}
		}

		return $next_step_id;
	}

	/**
	 * Get thank you page URL.
	 *
	 * @since 1.0.0
	 * @param int   $step_id step ID.
	 * @param array $data order data.
	 *
	 * @return string
	 */
	public function get_thankyou_page_url( $step_id, $data ) {

		$wcf_step_obj = wcf_pro_get_step( $step_id );
		$step_id      = intval( $step_id );
		$flow_id      = $wcf_step_obj->get_flow_id();
		$link         = '#';
		$order_id     = $data['order_id'];
		$order_key    = $data['order_key'];

		if ( ! $flow_id ) {
			return $link;
		}

		$thankyou_id = $wcf_step_obj->get_thankyou_page_id();

		if ( $thankyou_id ) {

			$this->may_be_complete_order( $thankyou_id, $order_id );

			$link = add_query_arg(
				array(
					'wcf-order' => $order_id,
					'wcf-key'   => $order_key,
				),
				get_permalink( $thankyou_id )
			);
		}

		return $link;
	}

	/**
	 * Check if upsell exists.
	 *
	 * @since 1.0.0
	 * @param object $order order data.
	 * @param int    $flow_id Flow Id.
	 * @param int    $step_id Step Id.
	 *
	 * @return bool
	 */
	public function check_if_next_step_is_offer( $order, $flow_id = 0, $step_id = 0 ) {

		$offer_step_exist = false;

		if ( $order ) {
			$step_id = wcf()->utils->get_checkout_id_from_order( $order );
		}

		if ( ! $flow_id ) {
			$flow_id = wcf()->utils->get_flow_id_from_order( $order );
		}

		$is_offer_exist_in_flow = $this->is_upsell_exist_in_flow( $flow_id, $step_id );

		if ( ! $is_offer_exist_in_flow ) {
			return $offer_step_exist;
		}

		$wcf_step_obj = wcf_pro_get_step( $step_id );
		$next_step_id = $wcf_step_obj->get_next_step_id();

		// Check if is next step upsell.
		$is_dynamic_rules = wcf()->options->get_checkout_meta_value( $step_id, 'wcf-checkout-rules-option' );

		if ( 'no' === $is_dynamic_rules ) {
			$wcf_next_step_obj = wcf_pro_get_step( $next_step_id );
			$offer_step_exist  = $wcf_next_step_obj->is_offer_page();
		} else {

			$next_step_id = apply_filters( 'cartflows_checkout_next_step_id', $next_step_id, $order, $step_id );

			$wcf_next_step_obj = wcf_pro_get_step( $next_step_id );
			$offer_step_exist  = $wcf_next_step_obj->is_offer_page();
		}

		return $offer_step_exist;
	}

	/**
	 * Check if upsell exists in flow.
	 *
	 * @since x.x.x
	 * @param int $flow_id Flow Id.
	 * @param int $step_id Step Id.
	 *
	 * @return bool
	 */
	public function is_upsell_exist_in_flow( $flow_id, $step_id ) {

		$offer_step_exist = false;

		if ( $flow_id && $step_id ) {

			$wcf_step_obj = wcf_pro_get_step( $step_id );

			$flow_steps = $wcf_step_obj->get_flow_steps();

			$control_step_id = $wcf_step_obj->get_control_step();

			if ( is_array( $flow_steps ) ) {

				$current_step_found = false;

				foreach ( $flow_steps as $index => $data ) {

					if ( $current_step_found ) {
						if ( in_array( $data['type'], array( 'upsell', 'downsell' ), true ) ) {

							$offer_step_exist = true;
							break;
						} elseif ( 'thankyou' === $data['type'] ) {
							break;
						}
					} else {
						// Check for the control step.
						if ( intval( $data['id'] ) === intval( $control_step_id ) ) {
							$current_step_found = true;
						}
					}
				}
			}
		}

		return $offer_step_exist;
	}

	/**
	 * Actions after offer charge completes.
	 *
	 * @since 1.0.0
	 * @param array $step_id step id.
	 * @param array $order_id order id.
	 * @param array $order_key order key.
	 * @param array $is_charge_success is charge successful.
	 * @param int   $variation_id variation id.
	 * @param int   $input_qty input qty.
	 *
	 * @return array
	 */
	public function after_offer_charge( $step_id, $order_id, $order_key, $is_charge_success = false, $variation_id = '', $input_qty = '' ) {

		$result = array();

		$step_type = wcf()->utils->get_step_type( $step_id );

		if ( $is_charge_success ) {

			$order = wc_get_order( $order_id );

			$offer_product = wcf_pro()->utils->get_offer_data( $step_id, $variation_id, $input_qty, $order_id );

			if ( 'upsell' === $step_type ) {
				/* Add Product To Main Order */
				wcf_pro()->order->add_upsell_product( $order, $offer_product );

			} else {
				wcf_pro()->order->add_downsell_product( $order, $offer_product );
			}

			do_action( 'cartflows_offer_accepted', $order, $offer_product );
			do_action( 'cartflows_' . $step_type . '_offer_accepted', $order, $offer_product );

			/**
			 * We need to reduce stock here.
			 *
			 * @todo
			 * reduce_stock();
			 */

			$data = array(
				'action'        => 'offer_accepted',
				'order_id'      => $order_id,
				'order_key'     => $order_key,
				'template_type' => $step_type,
			);

			/* Get Redirect URL */
			$next_step_url = wcf_pro()->flow->get_next_step_url( $step_id, $data );

			$result = array(
				'status'   => 'success',
				'redirect' => $next_step_url,
				'message'  => wcf_pro()->options->get_offers_meta_value( $step_id, 'wcf-offer-order-success-text' ),
			);

			wcf()->logger->log( 'Redirect URL : ' . $next_step_url );
			wcf()->logger->log( 'Order-' . $order_id . ' ' . $step_type . ' Offer accepted for step ID : ' . $step_id );
		} else {

			/* @todo if payment failed redirect to last page or not */
			$data = array(
				'order_id'  => $order_id,
				'order_key' => $order_key,
			);

			$thank_you_page_url = wcf_pro()->flow->get_thankyou_page_url( $step_id, $data );

			$result = array(
				'status'   => 'failed',
				'redirect' => $thank_you_page_url,
				'message'  => wcf_pro()->options->get_offers_meta_value( $step_id, 'wcf-offer-order-failure-text' ),
			);

			wcf()->logger->log( 'Order-' . $order_id . ' ' . $step_type . ' Offer Payment Failed. Redirected to thankyou step.' );
		}

		return $result;
	}
}

/**
 *  Kicking this off by calling 'get_instance()' method
 */
Cartflows_Pro_Flow_Frontend::get_instance();