@@ -2900,4 +2900,254 @@ public function test_prefers_developer_defined_target_hints() {
29002900 $ this ->assertArrayHasKey ( 'allow ' , $ link ['targetHints ' ] );
29012901 $ this ->assertSame ( array ( 'GET ' , 'PUT ' ), $ link ['targetHints ' ]['allow ' ] );
29022902 }
2903+
2904+ /**
2905+ * Registers a route for the response option tests, and a route that its link embeds.
2906+ *
2907+ * @param mixed $data The response data.
2908+ * @param bool $with_link Whether the response has an embeddable link.
2909+ * @param array<string, mixed> $handler_options Options for the route handler.
2910+ * @param array<string, mixed> $route_options Options for the route.
2911+ */
2912+ private function register_response_options_route ( $ data , bool $ with_link , array $ handler_options = array (), array $ route_options = array () ): void {
2913+ rest_get_server ()->register_route (
2914+ 'test-ns ' ,
2915+ '/test-ns/response-options ' ,
2916+ array_merge (
2917+ array (
2918+ array_merge (
2919+ array (
2920+ 'methods ' => 'GET ' ,
2921+ 'callback ' => static function () use ( $ data , $ with_link ) {
2922+ $ response = new WP_REST_Response ( $ data );
2923+ if ( $ with_link ) {
2924+ $ response ->add_link ( 'alternate ' , rest_url ( '/test-ns/embedded ' ), array ( 'embeddable ' => true ) );
2925+ }
2926+ return $ response ;
2927+ },
2928+ 'permission_callback ' => '__return_true ' ,
2929+ ),
2930+ $ handler_options
2931+ ),
2932+ ),
2933+ $ route_options
2934+ )
2935+ );
2936+
2937+ rest_get_server ()->register_route (
2938+ 'test-ns ' ,
2939+ '/test-ns/embedded ' ,
2940+ array (
2941+ 'methods ' => 'GET ' ,
2942+ 'callback ' => static function () {
2943+ return array ( 'hello ' => 'world ' );
2944+ },
2945+ 'permission_callback ' => '__return_true ' ,
2946+ )
2947+ );
2948+ }
2949+
2950+ /**
2951+ * Data provider for test_allow_fields_false_leaves_the_data_unfiltered().
2952+ *
2953+ * @return array<string, array{0: mixed, 1: string}>
2954+ */
2955+ public static function data_allow_fields_false_leaves_the_data_unfiltered (): array {
2956+ return array (
2957+ 'associative array ' => array (
2958+ array (
2959+ 'a ' => 1 ,
2960+ 'b ' => 2 ,
2961+ ),
2962+ '{"a":1,"b":2} ' ,
2963+ ),
2964+ 'list ' => array ( array ( array ( 'b ' => 2 ), 'c ' ), '[{"b":2},"c"] ' ),
2965+ 'empty object ' => array ( new stdClass (), '{} ' ),
2966+ 'object ' => array ( (object ) array ( 'b ' => 2 ), '{"b":2} ' ),
2967+ 'string ' => array ( 'value ' , '"value" ' ),
2968+ 'integer ' => array ( 5 , '5 ' ),
2969+ );
2970+ }
2971+
2972+ /**
2973+ * @ticket 66267
2974+ * @dataProvider data_allow_fields_false_leaves_the_data_unfiltered
2975+ *
2976+ * @param mixed $data The response data.
2977+ * @param string $expected The expected response body.
2978+ */
2979+ public function test_allow_fields_false_leaves_the_data_unfiltered ( $ data , string $ expected ): void {
2980+ $ this ->register_response_options_route ( $ data , false , array ( 'allow_fields ' => false ) );
2981+
2982+ $ _GET ['_fields ' ] = 'a ' ;
2983+ rest_get_server ()->serve_request ( '/test-ns/response-options ' );
2984+
2985+ $ this ->assertSame ( $ expected , rest_get_server ()->sent_body , 'The _fields parameter should not filter the data. ' );
2986+ }
2987+
2988+ /**
2989+ * @ticket 66267
2990+ */
2991+ public function test_fields_are_filtered_by_default (): void {
2992+ $ this ->register_response_options_route (
2993+ array (
2994+ 'a ' => 1 ,
2995+ 'b ' => 2 ,
2996+ ),
2997+ false
2998+ );
2999+
3000+ $ _GET ['_fields ' ] = 'a ' ;
3001+ rest_get_server ()->serve_request ( '/test-ns/response-options ' );
3002+
3003+ $ this ->assertSame ( '{"a":1} ' , rest_get_server ()->sent_body , 'The _fields parameter should filter the data. ' );
3004+ }
3005+
3006+ /**
3007+ * Data provider for test_allow_links_false_leaves_out_the_links().
3008+ *
3009+ * @return array<string, array{0: mixed, 1: string}>
3010+ */
3011+ public static function data_allow_links_false_leaves_out_the_links (): array {
3012+ return array (
3013+ 'associative array ' => array ( array ( 'a ' => 1 ), '{"a":1} ' ),
3014+ 'list ' => array ( array ( 'a ' , 'b ' ), '["a","b"] ' ),
3015+ 'empty object ' => array ( new stdClass (), '{} ' ),
3016+ 'string ' => array ( 'value ' , '"value" ' ),
3017+ );
3018+ }
3019+
3020+ /**
3021+ * @ticket 66267
3022+ * @dataProvider data_allow_links_false_leaves_out_the_links
3023+ *
3024+ * @param mixed $data The response data.
3025+ * @param string $expected The expected response body.
3026+ */
3027+ public function test_allow_links_false_leaves_out_the_links ( $ data , string $ expected ): void {
3028+ $ this ->register_response_options_route ( $ data , true , array ( 'allow_links ' => false ) );
3029+
3030+ rest_get_server ()->serve_request ( '/test-ns/response-options ' );
3031+
3032+ $ this ->assertSame ( $ expected , rest_get_server ()->sent_body , 'The response links should not be added. ' );
3033+ }
3034+
3035+ /**
3036+ * @ticket 66267
3037+ */
3038+ public function test_allow_embed_false_keeps_the_links_without_embedding (): void {
3039+ $ this ->register_response_options_route ( array ( 'a ' => 1 ), true , array ( 'allow_embed ' => false ) );
3040+
3041+ $ _GET ['_embed ' ] = '1 ' ;
3042+ rest_get_server ()->serve_request ( '/test-ns/response-options ' );
3043+ $ data = json_decode ( rest_get_server ()->sent_body , true );
3044+
3045+ $ this ->assertArrayHasKey ( '_links ' , $ data , 'The response links should be added. ' );
3046+ $ this ->assertArrayNotHasKey ( '_embedded ' , $ data , 'The links should not be embedded. ' );
3047+ }
3048+
3049+ /**
3050+ * @ticket 66267
3051+ */
3052+ public function test_links_are_added_and_embedded_by_default (): void {
3053+ $ this ->register_response_options_route ( array ( 'a ' => 1 ), true );
3054+
3055+ $ _GET ['_embed ' ] = '1 ' ;
3056+ rest_get_server ()->serve_request ( '/test-ns/response-options ' );
3057+ $ data = json_decode ( rest_get_server ()->sent_body , true );
3058+
3059+ $ this ->assertArrayHasKey ( '_links ' , $ data , 'The response links should be added. ' );
3060+ $ this ->assertSame ( array ( array ( 'hello ' => 'world ' ) ), $ data ['_embedded ' ]['alternate ' ], 'The link should be embedded. ' );
3061+ }
3062+
3063+ /**
3064+ * @ticket 66267
3065+ */
3066+ public function test_allow_embed_false_applies_to_enveloped_responses (): void {
3067+ $ this ->register_response_options_route ( array ( 'a ' => 1 ), true , array ( 'allow_embed ' => false ) );
3068+
3069+ $ _GET ['_embed ' ] = '1 ' ;
3070+ $ _GET ['_envelope ' ] = '1 ' ;
3071+ rest_get_server ()->serve_request ( '/test-ns/response-options ' );
3072+ $ data = json_decode ( rest_get_server ()->sent_body , true );
3073+
3074+ $ this ->assertSame ( 200 , $ data ['status ' ], 'The enveloped response should succeed. ' );
3075+ $ this ->assertArrayHasKey ( '_links ' , $ data ['body ' ], 'The response links should be added to the body. ' );
3076+ $ this ->assertArrayNotHasKey ( '_embedded ' , $ data ['body ' ], 'The links should not be embedded in the body. ' );
3077+ }
3078+
3079+ /**
3080+ * Data provider for test_handler_option_takes_precedence_over_route_option().
3081+ *
3082+ * @return array<string, array{0: array<string, bool>, 1: array<string, bool>, 2: string}>
3083+ */
3084+ public static function data_handler_option_takes_precedence_over_route_option (): array {
3085+ return array (
3086+ 'route disables ' => array ( array (), array ( 'allow_fields ' => false ), '{"a":1,"b":2} ' ),
3087+ 'route disables and handler enables ' => array ( array ( 'allow_fields ' => true ), array ( 'allow_fields ' => false ), '{"a":1} ' ),
3088+ 'route enables and handler disables ' => array ( array ( 'allow_fields ' => false ), array ( 'allow_fields ' => true ), '{"a":1,"b":2} ' ),
3089+ 'handler disables another option ' => array ( array ( 'allow_links ' => false ), array (), '{"a":1} ' ),
3090+ );
3091+ }
3092+
3093+ /**
3094+ * @ticket 66267
3095+ * @dataProvider data_handler_option_takes_precedence_over_route_option
3096+ *
3097+ * @param array<string, bool> $handler_options Options for the route handler.
3098+ * @param array<string, bool> $route_options Options for the route.
3099+ * @param string $expected The expected response body.
3100+ */
3101+ public function test_handler_option_takes_precedence_over_route_option ( array $ handler_options , array $ route_options , string $ expected ): void {
3102+ $ this ->register_response_options_route (
3103+ array (
3104+ 'a ' => 1 ,
3105+ 'b ' => 2 ,
3106+ ),
3107+ false ,
3108+ $ handler_options ,
3109+ $ route_options
3110+ );
3111+
3112+ $ _GET ['_fields ' ] = 'a ' ;
3113+ rest_get_server ()->serve_request ( '/test-ns/response-options ' );
3114+
3115+ $ this ->assertSame ( $ expected , rest_get_server ()->sent_body , 'The handler option should take precedence over the route option. ' );
3116+ }
3117+
3118+ /**
3119+ * @ticket 66267
3120+ */
3121+ public function test_response_options_apply_to_preloaded_requests (): void {
3122+ $ this ->register_response_options_route (
3123+ array (
3124+ 'a ' => 1 ,
3125+ 'b ' => 2 ,
3126+ ),
3127+ true ,
3128+ array (
3129+ 'allow_fields ' => false ,
3130+ 'allow_links ' => false ,
3131+ )
3132+ );
3133+
3134+ $ preload = rest_preload_api_request ( array (), '/test-ns/response-options?_fields=a&_embed=1 ' );
3135+
3136+ $ this ->assertSame (
3137+ array (
3138+ 'a ' => 1 ,
3139+ 'b ' => 2 ,
3140+ ),
3141+ $ preload ['/test-ns/response-options?_fields=a&_embed=1 ' ]['body ' ],
3142+ 'The preloaded data should not be filtered or have links. '
3143+ );
3144+ }
3145+
3146+ /**
3147+ * @ticket 66267
3148+ */
3149+ public function test_is_response_option_enabled_without_a_matched_route (): void {
3150+ $ this ->assertTrue ( rest_get_server ()->is_response_option_enabled ( new WP_REST_Response (), 'allow_fields ' ), 'A response without a matched route should enable the option. ' );
3151+ $ this ->assertTrue ( rest_get_server ()->is_response_option_enabled ( new WP_HTTP_Response (), 'allow_links ' ), 'A response that is not a REST response should enable the option. ' );
3152+ }
29033153}
0 commit comments