From 8a0699edc87921d676d5a1b3189a2cf881ffc624 Mon Sep 17 00:00:00 2001 From: faisalahammad Date: Wed, 19 Aug 2026 22:48:04 +0600 Subject: [PATCH] test: add regression coverage for Media pod REST save Locks in the fix for #6420. PodsRESTFields::register() maps the 'media' pod to the 'attachment' object type, so PodsRESTHandlers::save_handler() must look up $wp_rest_additional_fields by object type rather than by pod name. Reverting that lookup to the pod name leaves the array empty and this test fails, so it is a real guard rather than a restatement. Refs #6420 --- .../wpunit/Pods/PodsRESTHandlersMediaTest.php | 211 ++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 tests/codeception/wpunit/Pods/PodsRESTHandlersMediaTest.php diff --git a/tests/codeception/wpunit/Pods/PodsRESTHandlersMediaTest.php b/tests/codeception/wpunit/Pods/PodsRESTHandlersMediaTest.php new file mode 100644 index 0000000000..17dc49e233 --- /dev/null +++ b/tests/codeception/wpunit/Pods/PodsRESTHandlersMediaTest.php @@ -0,0 +1,211 @@ +media_pod_id = $api->save_pod( [ + 'type' => 'media', + 'storage' => 'meta', + 'public' => 1, + 'supports_custom_fields' => 1, + 'rest_enable' => 1, + 'name' => 'media', + ] ); + + $this->media_group_id = $api->save_group( [ + 'pod_id' => $this->media_pod_id, + 'name' => 'media-checksum', + ] ); + + // Field name mirrors the reporter's "checksum" example. + $api->save_field( [ + 'pod_id' => $this->media_pod_id, + 'group_id' => $this->media_group_id, + 'name' => 'media_checksum', + 'label' => 'Checksum', + 'type' => 'text', + 'rest_read' => 1, + 'rest_write' => 1, + ] ); + + $this->media_pod = $api->load_pod( [ + 'id' => $this->media_pod_id, + ] ); + + // Create a real attachment so save_handler can resolve the WP_Post. + $this->attachment_id = wp_insert_attachment( [ + 'post_type' => 'attachment', + 'post_mime_type' => 'image/png', + 'post_title' => 'Test attachment', + 'post_status' => 'inherit', + ] ); + } + + public function tearDown(): void { + $this->media_pod_id = 0; + $this->media_group_id = 0; + $this->attachment_id = 0; + $this->media_pod = null; + + // Reset the current user between tests. + global $current_user; + $current_user = null; + wp_set_current_user( 0 ); + + parent::tearDown(); + } + + /** + * It should register the media pod field under the 'attachment' key + * in $wp_rest_additional_fields, not the pod name 'media'. + * + * @test + */ + public function should_register_field_under_attachment_key() { + global $wp_rest_additional_fields; + + $this->register_media_pod_rest_field(); + + $this->assertArrayHasKey( 'attachment', $wp_rest_additional_fields ); + $this->assertArrayHasKey( 'media_checksum', $wp_rest_additional_fields['attachment'] ); + + // Must NOT be registered under the pod name 'media' (that would + // indicate the regression from issue #6420). + $this->assertArrayNotHasKey( 'media', $wp_rest_additional_fields ); + + $field_args = $wp_rest_additional_fields['attachment']['media_checksum']; + + $this->assertTrue( ! empty( $field_args['pods_update'] ) ); + $this->assertNotEmpty( $field_args['get_callback'] ); + } + + /** + * It should persist a media pod field when save_handler() is invoked. + * + * Reproduces issue #6420: prior to the fix, save_handler keyed + * $wp_rest_additional_fields by $pod_name ('media') and never matched + * the field registered under 'attachment', so the value was never + * saved. + * + * @test + */ + public function should_save_field_on_media_pod_via_save_handler() { + $this->register_media_pod_rest_field(); + + // Build a request that includes the field value, the way a real + // REST POST would after WP_REST_Server has parsed the body. + $request = new WP_REST_Request( 'POST', '/wp/v2/media/' . $this->attachment_id ); + $request->set_param( 'media_checksum', '42' ); + + $post = get_post( $this->attachment_id ); + + PodsRESTHandlers::save_handler( $post, $request, false ); + + $this->assertEquals( '42', get_post_meta( $this->attachment_id, 'media_checksum', true ) ); + } + + /** + * It should read the saved value back through get_handler(), matching + * the read path the reporter saw work correctly. + * + * @test + */ + public function should_read_field_via_get_handler_after_save() { + $this->register_media_pod_rest_field(); + + $request = new WP_REST_Request( 'GET', '/wp/v2/media/' . $this->attachment_id ); + $request->set_param( 'media_checksum', '42' ); + + $post = get_post( $this->attachment_id ); + + PodsRESTHandlers::save_handler( $post, $request, false ); + + $value = PodsRESTHandlers::get_handler( + $post->to_array(), + 'media_checksum', + $request, + 'attachment' + ); + + $this->assertSame( '42', $value ); + } + + /** + * Reset any stale rest_api_init registrations from prior tests in + * this class, then instantiate PodsRESTFields for the media pod and + * fire rest_api_init so the field is registered against the + * 'attachment' object type. + * + * Each test calls this in isolation so a prior instance of + * PodsRESTFields (which caches a reference to its pod) cannot leak + * into the current test. + */ + private function register_media_pod_rest_field(): void { + global $wp_rest_additional_fields; + + // Only the $wp_rest_additional_fields reset is needed to isolate + // rest_api_init registrations across tests in this class; the + // WPTestCase base rolls back $wp_filter between cases. + $wp_rest_additional_fields = []; + + // Instantiating PodsRESTFields hooks add_fields() onto rest_api_init. + new PodsRESTFields( $this->media_pod ); + + do_action( 'rest_api_init' ); + } +}