get( 'analytics_enable_behavior_tracking', true ) ) ) { return; } if ( get_option( 'accessiq_analytics_exclude_logged_in', $s->get( 'analytics_exclude_logged_in', false ) ) && is_user_logged_in() ) { return; } wp_enqueue_script( 'accessiq-behavior', ACCESSIQ_URL . 'public/js/behavior.js', array(), ACCESSIQ_VERSION, true ); $page_url = get_permalink(); if ( ! $page_url ) { $page_url = home_url( isset( $_SERVER['REQUEST_URI'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '' ); } wp_localize_script( 'accessiq-behavior', 'accessiqBehavior', array( 'ajax_url' => admin_url( 'admin-ajax.php' ), 'nonce' => accessiq_tracking_token(), 'page_url' => (string) $page_url, ) ); } /** * Handle session start AJAX request. */ public function handle_session_start() { if ( ! accessiq_verify_tracking_request() ) { wp_send_json_error( 'Invalid nonce' ); } if ( accessiq_is_bot_request() || accessiq_tracking_rate_limited() ) { wp_send_json_error( 'Throttled' ); } global $wpdb; $session_id = isset( $_POST['session_id'] ) ? accessiq_clean_session_id( $_POST['session_id'] ) : ''; $page_url = isset( $_POST['page_url'] ) ? esc_url_raw( wp_unslash( $_POST['page_url'] ) ) : ''; $referrer = isset( $_POST['referrer'] ) ? esc_url_raw( wp_unslash( $_POST['referrer'] ) ) : ''; $device_type = isset( $_POST['device_type'] ) ? sanitize_text_field( wp_unslash( $_POST['device_type'] ) ) : 'desktop'; if ( empty( $session_id ) || empty( $page_url ) ) { wp_send_json_error( 'Missing data' ); } if ( strpos( $page_url, '/wp-' ) !== false ) { wp_send_json_error( 'Internal URL ignored' ); } $table_name = $wpdb->prefix . 'accessiq_sessions'; $wpdb->query( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching $wpdb->prepare( // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared 'INSERT IGNORE INTO `' . esc_sql( $table_name ) . '` (session_id, page_url, time_spent, is_bounce, referrer, device_type, created_at, updated_at) VALUES (%s, %s, %d, %d, %s, %s, %s, %s)', $session_id, $page_url, 0, 1, $referrer, $device_type, current_time( 'mysql' ), current_time( 'mysql' ) ) ); wp_send_json_success( 'Session started' ); } /** * Handle session update (time spent + bounce). */ public function handle_session_update() { if ( ! accessiq_verify_tracking_request() ) { wp_send_json_error( 'Invalid nonce' ); } if ( accessiq_is_bot_request() || accessiq_tracking_rate_limited() ) { wp_send_json_error( 'Throttled' ); } global $wpdb; $session_id = isset( $_POST['session_id'] ) ? accessiq_clean_session_id( $_POST['session_id'] ) : ''; $page_url = isset( $_POST['page_url'] ) ? esc_url_raw( wp_unslash( $_POST['page_url'] ) ) : ''; $time_spent = isset( $_POST['time_spent'] ) ? absint( $_POST['time_spent'] ) : 0; $is_bounce = isset( $_POST['is_bounce'] ) ? absint( $_POST['is_bounce'] ) : 1; if ( empty( $session_id ) || empty( $page_url ) ) { wp_send_json_error( 'Missing data' ); } $table_name = $wpdb->prefix . 'accessiq_sessions'; $wpdb->query( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching $wpdb->prepare( // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared 'UPDATE `' . esc_sql( $table_name ) . '` SET time_spent = %d, is_bounce = %d, updated_at = %s WHERE session_id = %s AND page_url = %s', $time_spent, $is_bounce, current_time( 'mysql' ), $session_id, $page_url ) ); // Multi-page sessions: clear bounce on every page row for this session. if ( 0 === (int) $is_bounce ) { $wpdb->query( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching $wpdb->prepare( // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared 'UPDATE `' . esc_sql( $table_name ) . '` SET is_bounce = 0 WHERE session_id = %s', $session_id ) ); } wp_send_json_success( 'Session updated' ); } /** * Handle page view recording for Journey Tracker. */ public function ajax_record_page_view() { if ( ! accessiq_verify_tracking_request() ) { wp_send_json_error( 'Invalid nonce' ); } if ( accessiq_is_bot_request() || accessiq_tracking_rate_limited() ) { wp_send_json_error( 'Throttled' ); } global $wpdb; $session_id = isset( $_POST['session_id'] ) ? accessiq_clean_session_id( $_POST['session_id'] ) : ''; $page_url = isset( $_POST['page_url'] ) ? esc_url_raw( wp_unslash( $_POST['page_url'] ) ) : ''; $page_title = isset( $_POST['page_title'] ) ? sanitize_text_field( wp_unslash( $_POST['page_title'] ) ) : ''; $time_spent = isset( $_POST['time_spent'] ) ? absint( $_POST['time_spent'] ) : 0; $scroll_depth = isset( $_POST['scroll_depth'] ) ? min( 100, absint( $_POST['scroll_depth'] ) ) : 0; if ( empty( $session_id ) || empty( $page_url ) ) { wp_send_json_error( 'Missing data' ); } if ( strpos( $page_url, '/wp-' ) !== false ) { wp_send_json_error( 'Internal URL ignored' ); } $table_name = $wpdb->prefix . 'accessiq_page_views'; $wpdb->insert( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery $table_name, array( 'session_id' => $session_id, 'page_url' => $page_url, 'page_title' => $page_title, 'time_spent' => $time_spent, 'scroll_depth' => $scroll_depth, 'created_at' => current_time( 'mysql' ), ), array( '%s', '%s', '%s', '%d', '%d', '%s' ) ); wp_send_json_success( 'Page view recorded' ); } }