@@ -361,24 +361,16 @@ public static function handle_ping( WP_REST_Request $request ) {
361361 * @return WP_REST_Response Response data.
362362 */
363363 public static function list_sessions ( WP_REST_Request $ request ) {
364- $ ability = self ::require_ability ( 'datamachine/list-chat-sessions ' );
365- if ( is_wp_error ( $ ability ) ) {
366- return $ ability ;
367- }
368-
369- $ agent_id = PermissionHelper::resolve_scoped_agent_id ( $ request );
370-
371- $ result = $ ability ->execute (
364+ return self ::execute_ability (
365+ 'datamachine/list-chat-sessions ' ,
372366 array (
373367 'user_id ' => get_current_user_id (),
374- 'agent_id ' => $ agent_id ,
368+ 'agent_id ' => PermissionHelper:: resolve_scoped_agent_id ( $ request ) ,
375369 'limit ' => (int ) $ request ->get_param ( 'limit ' ),
376370 'offset ' => (int ) $ request ->get_param ( 'offset ' ),
377371 'context ' => $ request ->get_param ( 'context ' ),
378372 )
379373 );
380-
381- return self ::ability_response ( $ result , 'list_sessions_failed ' );
382374 }
383375
384376 /**
@@ -390,19 +382,13 @@ public static function list_sessions( WP_REST_Request $request ) {
390382 * @return WP_REST_Response|WP_Error Response data or error.
391383 */
392384 public static function mark_session_read ( WP_REST_Request $ request ) {
393- $ ability = self ::require_ability ( 'datamachine/mark-session-read ' );
394- if ( is_wp_error ( $ ability ) ) {
395- return $ ability ;
396- }
397-
398- $ result = $ ability ->execute (
385+ return self ::execute_ability (
386+ 'datamachine/mark-session-read ' ,
399387 array (
400388 'session_id ' => sanitize_text_field ( $ request ->get_param ( 'session_id ' ) ),
401389 'user_id ' => get_current_user_id (),
402390 )
403391 );
404-
405- return self ::ability_response ( $ result , 'mark_read_failed ' );
406392 }
407393
408394 /**
@@ -412,19 +398,13 @@ public static function mark_session_read( WP_REST_Request $request ) {
412398 * @return WP_REST_Response|WP_Error Response data or error.
413399 */
414400 public static function delete_session ( WP_REST_Request $ request ) {
415- $ ability = self ::require_ability ( 'datamachine/delete-chat-session ' );
416- if ( is_wp_error ( $ ability ) ) {
417- return $ ability ;
418- }
419-
420- $ result = $ ability ->execute (
401+ return self ::execute_ability (
402+ 'datamachine/delete-chat-session ' ,
421403 array (
422404 'session_id ' => sanitize_text_field ( $ request ->get_param ( 'session_id ' ) ),
423405 'user_id ' => get_current_user_id (),
424406 )
425407 );
426-
427- return self ::ability_response ( $ result , 'delete_failed ' );
428408 }
429409
430410 /**
@@ -434,19 +414,13 @@ public static function delete_session( WP_REST_Request $request ) {
434414 * @return WP_REST_Response|WP_Error Response data or error.
435415 */
436416 public static function get_session ( WP_REST_Request $ request ) {
437- $ ability = self ::require_ability ( 'datamachine/get-chat-session ' );
438- if ( is_wp_error ( $ ability ) ) {
439- return $ ability ;
440- }
441-
442- $ result = $ ability ->execute (
417+ return self ::execute_ability (
418+ 'datamachine/get-chat-session ' ,
443419 array (
444420 'session_id ' => sanitize_text_field ( $ request ->get_param ( 'session_id ' ) ),
445421 'user_id ' => get_current_user_id (),
446422 )
447423 );
448-
449- return self ::ability_response ( $ result , 'get_failed ' );
450424 }
451425
452426 /**
@@ -681,24 +655,23 @@ private static function resolve_attachment_paths( array $attachments ): array {
681655 }
682656
683657 /**
684- * Resolve an ability by slug, returning WP_Error if unavailable.
658+ * Execute an ability and return the REST response.
659+ *
660+ * Resolves the ability by slug, calls execute() with the given input,
661+ * and converts the result into a REST response. Handles WP_Error returns
662+ * from core's execute() pipeline (input validation, permissions, callback).
685663 *
686- * Centralizes the guard so handlers never duplicate the check.
664+ * For ability callbacks that still return { success: false, error: ... }
665+ * arrays (legacy convention), those are mapped to WP_Error. New abilities
666+ * should return WP_Error directly per core best practices.
687667 *
688668 * @since 0.62.0
689669 *
690- * @param string $slug Ability slug (e.g. 'datamachine/get-chat-session').
691- * @return \WP_Ability|WP_Error The ability instance or an error.
670+ * @param string $slug Ability slug (e.g. 'datamachine/get-chat-session').
671+ * @param array $input Input parameters for the ability.
672+ * @return WP_REST_Response|WP_Error
692673 */
693- private static function require_ability ( string $ slug ) {
694- if ( ! function_exists ( 'wp_get_ability ' ) ) {
695- return new WP_Error (
696- 'ability_unavailable ' ,
697- __ ( 'Abilities API not loaded. ' , 'data-machine ' ),
698- array ( 'status ' => 500 )
699- );
700- }
701-
674+ private static function execute_ability ( string $ slug , array $ input = array () ) {
702675 $ ability = wp_get_ability ( $ slug );
703676
704677 if ( ! $ ability ) {
@@ -710,40 +683,35 @@ private static function require_ability( string $slug ) {
710683 );
711684 }
712685
713- return $ ability ;
714- }
686+ $ result = $ ability ->execute ( $ input );
715687
716- /**
717- * Convert an ability result array into a REST response.
718- *
719- * On success wraps in `{ success: true, data: ... }`.
720- * On failure maps the error code to an appropriate HTTP status.
721- *
722- * @since 0.62.0
723- *
724- * @param array $result Ability execute() return value.
725- * @param string $default_error Fallback error code when result has none.
726- * @return WP_REST_Response|WP_Error
727- */
728- private static function ability_response ( array $ result , string $ default_error = 'ability_failed ' ) {
729- if ( ! empty ( $ result ['success ' ] ) ) {
730- return rest_ensure_response (
731- array (
732- 'success ' => true ,
733- 'data ' => $ result ,
734- )
735- );
688+ // Core's execute() returns WP_Error for validation/permission/callback failures.
689+ if ( is_wp_error ( $ result ) ) {
690+ return $ result ;
736691 }
737692
738- $ error_code = $ result ['error ' ] ?? $ default_error ;
693+ // Legacy convention: ability callbacks return { success: false, error: ... }.
694+ // Map to WP_Error until all abilities are migrated to return WP_Error directly.
695+ if ( is_array ( $ result ) && isset ( $ result ['success ' ] ) && ! $ result ['success ' ] ) {
696+ $ error_code = $ result ['error ' ] ?? 'ability_failed ' ;
739697
740- $ status_map = array (
741- 'session_not_found ' => 404 ,
742- 'session_access_denied ' => 403 ,
743- );
698+ $ status_map = array (
699+ 'session_not_found ' => 404 ,
700+ 'session_access_denied ' => 403 ,
701+ );
744702
745- $ status = $ status_map [ $ error_code ] ?? 500 ;
703+ return new WP_Error (
704+ $ error_code ,
705+ $ result ['error ' ] ?? 'Ability execution failed. ' ,
706+ array ( 'status ' => $ status_map [ $ error_code ] ?? 500 )
707+ );
708+ }
746709
747- return new WP_Error ( $ error_code , $ result ['error ' ] ?? $ default_error , array ( 'status ' => $ status ) );
710+ return rest_ensure_response (
711+ array (
712+ 'success ' => true ,
713+ 'data ' => $ result ,
714+ )
715+ );
748716 }
749717}
0 commit comments