'POST', 'permission_callback' => static function () : bool { return current_user_can( 'manage_options' ); }, 'callback' => 'abtestkit_connected_wizard_collect', ) ); } add_action( 'rest_api_init', 'abtestkit_connected_wizard_register_route' ); /** * Queue one unique reached-step event without making a service request. * * @param WP_REST_Request $request REST request. * @return WP_REST_Response|WP_Error */ function abtestkit_connected_wizard_collect( WP_REST_Request $request ) { if ( ! abtestkit_connected_platform_can_create_or_launch() ) { return abtestkit_connected_platform_required_error(); } $input = $request->get_json_params(); if ( ! is_array( $input ) ) { return new WP_Error( 'abtestkit_connected_wizard_invalid', __( 'The wizard milestone is invalid.', 'abtestkit' ), array( 'status' => 400 ) ); } $keys = array_keys( $input ); sort( $keys ); if ( array( 'goal', 'kind', 'session_id', 'step' ) !== $keys ) { return new WP_Error( 'abtestkit_connected_wizard_invalid', __( 'The wizard milestone is invalid.', 'abtestkit' ), array( 'status' => 400 ) ); } $session_id = is_string( $input['session_id'] ) ? $input['session_id'] : ''; $step = is_string( $input['step'] ) ? $input['step'] : ''; $kind = is_string( $input['kind'] ) ? $input['kind'] : ''; $goal = is_string( $input['goal'] ) ? $input['goal'] : ''; if ( 1 !== preg_match( '/^ws_[a-f0-9]{32}$/D', $session_id ) || ! in_array( $step, array( 'select_type', 'select_custom_code_type', 'select_control', 'version_b_source', 'review_versions', 'choose_conversion_type', 'set_destination_url', 'set_scroll_depth', 'select_click_targets', 'summary' ), true ) || ! in_array( $kind, array( 'unknown', 'page', 'post', 'product', 'reusable_section', 'custom_css', 'custom_html', 'custom_javascript' ), true ) || ! in_array( $goal, array( 'unknown', 'clicks', 'form', 'destination_url', 'scroll_depth', 'add_to_cart', 'purchase' ), true ) ) { return new WP_Error( 'abtestkit_connected_wizard_invalid', __( 'The wizard milestone is invalid.', 'abtestkit' ), array( 'status' => 400 ) ); } $connection = abtestkit_hosted_get_connection(); $installation = ABTestKit_Connected_Installation::get_or_create(); if ( ! is_array( $connection ) || is_wp_error( $installation ) ) { abtestkit_connected_collection_gap( 'wizard_identity_unavailable' ); return new WP_Error( 'abtestkit_connected_wizard_unavailable', __( 'The wizard milestone could not be recorded.', 'abtestkit' ), array( 'status' => 503 ) ); } $site_ref = (string) ( $connection['site_ref'] ?? '' ); if ( 1 !== preg_match( '/^[a-f0-9]{32}$/D', $site_ref ) ) { return new WP_Error( 'abtestkit_connected_wizard_unavailable', __( 'The wizard milestone could not be recorded.', 'abtestkit' ), array( 'status' => 503 ) ); } $dedupe_key = 'abtestkit_wizard_event_' . hash( 'sha256', $site_ref . '|' . $session_id . '|' . $step ); $record = get_transient( $dedupe_key ); if ( is_array( $record ) && true === ( $record['queued'] ?? false ) ) { return rest_ensure_response( array( 'accepted' => true ) ); } if ( ! is_array( $record ) || ! isset( $record['event'] ) || ! is_array( $record['event'] ) ) { $event_id = ABTestKit_Connected_Event::new_id(); if ( is_wp_error( $event_id ) ) { abtestkit_connected_collection_gap( $event_id->get_error_code() ); return new WP_Error( 'abtestkit_connected_wizard_unavailable', __( 'The wizard milestone could not be recorded.', 'abtestkit' ), array( 'status' => 503 ) ); } $session_ref = 'wizard_' . substr( hash_hmac( 'sha256', $site_ref . '|' . $session_id, (string) $installation['installation_id'] ), 0, 32 ); $record = array( 'queued' => false, 'event' => array( 'schema_version' => 1, 'event_id' => $event_id, 'installation_id' => (string) $installation['installation_id'], 'event_name' => 'wizard_step_reached', 'occurred_at' => time(), 'plugin_version' => abtestkit_hosted_sync_plugin_version(), 'test_ref' => null, 'payload' => array( 'evidence' => 'observed', 'goal' => $goal, 'kind' => $kind, 'session_ref' => $session_ref, 'step' => $step, ), ), ); set_transient( $dedupe_key, $record, ABTestKit_Connected_Event::MAX_AGE ); } $event = ABTestKit_Connected_Event::validate( $record['event'], time() ); if ( is_wp_error( $event ) ) { delete_transient( $dedupe_key ); abtestkit_connected_collection_gap( 'wizard_event_invalid' ); return new WP_Error( 'abtestkit_connected_wizard_unavailable', __( 'The wizard milestone could not be recorded.', 'abtestkit' ), array( 'status' => 503 ) ); } if ( 1 !== (int) get_option( ABTestKit_Connected_Outbox::SCHEMA_OPTION, 0 ) ) { $installed = ABTestKit_Connected_Outbox::install(); if ( is_wp_error( $installed ) ) { abtestkit_connected_collection_gap( $installed->get_error_code() ); return new WP_Error( 'abtestkit_connected_wizard_unavailable', __( 'The wizard milestone could not be recorded.', 'abtestkit' ), array( 'status' => 503 ) ); } } $queued = ABTestKit_Connected_Outbox::enqueue( $event, time() ); if ( is_wp_error( $queued ) ) { abtestkit_connected_collection_gap( $queued->get_error_code() ); return new WP_Error( 'abtestkit_connected_wizard_unavailable', __( 'The wizard milestone could not be recorded.', 'abtestkit' ), array( 'status' => 503 ) ); } $record['queued'] = true; set_transient( $dedupe_key, $record, ABTestKit_Connected_Event::MAX_AGE ); abtestkit_connected_transport_schedule(); return rest_ensure_response( array( 'accepted' => true ) ); }