service = $service ?? new AbandonedCartService(); } /** * Register hooks. * * @return void */ public function register(): void { if ( ! class_exists( 'WooCommerce' ) ) { return; } add_action( 'woocommerce_add_to_cart', array( $this, 'captureCartData' ) ); add_action( 'woocommerce_cart_updated', array( $this, 'cartUpdated' ) ); add_action( 'woocommerce_checkout_update_order_review', array( $this, 'captureCheckoutEmail' ) ); add_action( 'wp_enqueue_scripts', array( $this, 'enqueueCheckoutEmailCapture' ) ); add_filter( 'cron_schedules', array( $this, 'addCronSchedule' ) ); add_action( self::CRON_HOOK, array( $this, 'processAbandonedCarts' ) ); if ( ! wp_next_scheduled( self::CRON_HOOK ) ) { wp_schedule_event( time() + MINUTE_IN_SECONDS, self::CRON_INTERVAL, self::CRON_HOOK ); } add_action( 'woocommerce_thankyou', array( $this, 'markCartRecoveredThankyou' ), 10, 1 ); //add_action( 'woocommerce_payment_complete', array( $this, 'markCartRecoveredThankyou' ), 10, 1 ); add_action( 'woocommerce_checkout_order_processed', array( $this, 'markCartRecoveredAfterCheckout' ), 10, 3 ); // Add actions to recover cart add_action( 'afromewo_recover_cart', array( $this, 'recoverCart' ) ); add_action( 'nopriv_afromewo_recover_cart', array( $this, 'recoverCart' ) ); add_action( 'wp_loaded', function() { // Only proceed if not in admin and correct params are set for cart recovery if ( ! is_admin() && '' !== Request::get( 'afromewo_recover_cart', '' ) ) { if (is_user_logged_in()) { do_action('afromewo_recover_cart'); } else { do_action('nopriv_afromewo_recover_cart'); } exit; } } ); } /** * Add custom cron interval. * * @param array> $schedules Cron schedules. * @return array> */ public function addCronSchedule( array $schedules ): array { $schedules[ self::CRON_INTERVAL ] = array( 'interval' => 300, 'display' => __( 'Every Five Minutes', 'afroit-messaging-workflows' ), ); return $schedules; } /** * Persist cart snapshot for the current session (add to cart / cart changes). * * @return void */ public function captureCartData(): void { if ( ! WC()->cart || WC()->cart->is_empty() || ! WC()->session ) { return; } $session_id = WC()->session->get_customer_id(); if ( '' === $session_id ) { return; } $email = ''; $phone = null; if ( WC()->customer ) { $email = (string) WC()->customer->get_billing_email(); $phone_raw = trim( (string) WC()->customer->get_billing_phone() ); $phone = '' !== $phone_raw ? $phone_raw : null; } $user_id = get_current_user_id() ?: null; $this->service->captureCart( $session_id, $email, $phone, $user_id ); } /** * @return void */ public function cartUpdated(): void { $this->captureCartData(); } /** * Refresh snapshot when checkout totals review runs (captures billing email/phone when available). * * @return void */ public function captureCheckoutEmail(): void { if ( ! WC()->cart || WC()->cart->is_empty() || ! WC()->session ) { return; } $session_id = WC()->session->get_customer_id(); if ( '' === $session_id ) { return; } $email = ''; $phone = null; if ( WC()->customer ) { $email = (string) WC()->customer->get_billing_email(); $phone_raw = trim( (string) WC()->customer->get_billing_phone() ); $phone = '' !== $phone_raw ? $phone_raw : null; } $user_id = get_current_user_id() ?: null; $this->service->captureCart( $session_id, $email, $phone, $user_id ); } /** * Enqueue checkout email and phone capture script for classic and block checkout. * * @return void */ public function enqueueCheckoutEmailCapture(): void { if ( ! is_checkout() ) { return; } $use_raw_assets = defined('AFROMEWO_DEV_MODE') && constant('AFROMEWO_DEV_MODE'); if ($use_raw_assets) { $relative_path = 'assets/js/frontend/checkout-email-capture.js'; } else { $relative_path = 'assets/build/frontend.bundle.min.js'; } $asset_path = AFROMEWO_PLUGIN_DIR . $relative_path; wp_enqueue_script( 'afromewo-checkout-email-capture', AFROMEWO_PLUGIN_URL . $relative_path, array(), is_readable( $asset_path ) ? (string) filemtime( $asset_path ) : AFROMEWO_VERSION, true ); wp_localize_script( 'afromewo-checkout-email-capture', 'AfroitMessagingWorkflowCartCapture', array( 'ajaxUrl' => admin_url( 'admin-ajax.php' ), 'nonce' => wp_create_nonce( 'capture_cart_email' ), ) ); } /** * @param int $order_id Order ID. * @return void */ public function markCartRecoveredThankyou( $order_id ): void { $order = wc_get_order( absint( $order_id ) ); if ( $order instanceof \WC_Order ) { $this->service->markRecovered( $order ); } } /** * @param int $order_id Order ID. * @param array $posted_data Posted checkout data. * @param \WC_Order|null $order Order object. * @return void */ public function markCartRecoveredAfterCheckout( $order_id, $posted_data, $order = null ): void { if ( $order instanceof \WC_Order ) { $this->service->markRecovered( $order ); return; } $o = wc_get_order( absint( $order_id ) ); if ( $o instanceof \WC_Order ) { $this->service->markRecovered( $o ); } } /** * Process abandoned carts via cron. * * @return void */ public function processAbandonedCarts(): void { $this->service->processAbandonedCarts(); } public function recoverCart(): void { $token = Request::get( 'afromewo_recover_cart', '' ); Log::info( 'Recover cart token: ' . $token ); if ( '' === $token ) { wp_safe_redirect( home_url() ); exit; } try { $recovered = $this->service->recoverCart( $token ); if ( ! $recovered ) { wp_safe_redirect( home_url() ); exit; } wp_safe_redirect( wc_get_cart_url() ); } catch ( \Exception $e ) { Log::error( 'Error recovering cart (general error): ' . $e->getMessage(), array( 'token' => $token ) ); wp_safe_redirect( home_url() ); } exit; } }