'POST', 'callback' => array( $this, 'track_play' ), 'permission_callback' => '__return_true', 'args' => array( 'src' => array( 'type' => 'string', 'required' => true, 'sanitize_callback' => 'esc_url_raw', ), 'title' => array( 'type' => 'string', 'required' => false, 'sanitize_callback' => 'sanitize_text_field', ), 'hash' => array( 'type' => 'string', 'required' => true, 'sanitize_callback' => 'sanitize_text_field', ), 'nonce' => array( 'type' => 'string', 'required' => true, 'sanitize_callback' => 'sanitize_text_field', ), ), ) ); } /** * Persist a play event. * * @param WP_REST_Request $request Request object. * @return WP_REST_Response|WP_Error */ public function track_play( WP_REST_Request $request ) { $src = (string) $request->get_param( 'src' ); $title = (string) $request->get_param( 'title' ); $hash = (string) $request->get_param( 'hash' ); $nonce = (string) $request->get_param( 'nonce' ); if ( empty( $src ) || empty( $hash ) || empty( $nonce ) ) { return new WP_Error( 'map_invalid_request', __( 'Missing analytics parameters.', 'modern-audio-player' ), array( 'status' => 400 ) ); } if ( Analytics::build_source_hash( $src ) !== $hash ) { return new WP_Error( 'map_invalid_hash', __( 'Audio source validation failed.', 'modern-audio-player' ), array( 'status' => 400 ) ); } if ( ! wp_verify_nonce( $nonce, 'map_track_play_' . $hash ) ) { return new WP_Error( 'map_invalid_nonce', __( 'Analytics nonce validation failed.', 'modern-audio-player' ), array( 'status' => 403 ) ); } Analytics::record_play( $src, $title ); return new WP_REST_Response( array( 'success' => true, ), 200 ); } }