Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Respect empty multiselect creation meta (#122)
  • Loading branch information
priethor committed May 26, 2026
commit cddd6425b958a822b5ae3df2cd63fb58aebcfa05
18 changes: 12 additions & 6 deletions includes/Fields/FieldDefaults.php
Original file line number Diff line number Diff line change
Expand Up @@ -171,13 +171,15 @@ public static function normalize( mixed $raw, string $type, ?array $option_value
/**
* Applies all supported defaults for a collection to one newly-created row.
*
* @param int $collection_id Collection post id.
* @param int $row_id Row post id.
* @param int $collection_id Collection post id.
* @param int $row_id Row post id.
* @param string[] $explicit_meta_keys Field meta keys explicitly provided during creation.
*/
public static function apply_to_row( int $collection_id, int $row_id ): void {
$field_ids = array_map( 'intval', get_post_meta( $collection_id, 'fields', false ) );
$store = new FieldValueStore();
$status = (string) get_post_status( $row_id );
public static function apply_to_row( int $collection_id, int $row_id, array $explicit_meta_keys = array() ): void {
$field_ids = array_map( 'intval', get_post_meta( $collection_id, 'fields', false ) );
$explicit_meta_keys = array_fill_keys( array_map( 'strval', $explicit_meta_keys ), true );
$store = new FieldValueStore();
$status = (string) get_post_status( $row_id );

foreach ( $field_ids as $field_id ) {
$type = (string) get_post_meta( $field_id, 'type', true );
Expand All @@ -186,6 +188,10 @@ public static function apply_to_row( int $collection_id, int $row_id ): void {
}

$key = Relations::meta_key( $field_id );
if ( isset( $explicit_meta_keys[ $key ] ) ) {
continue;
}

if ( count( get_metadata( 'post', $row_id, $key, false ) ) > 0 ) {
continue;
}
Expand Down
63 changes: 62 additions & 1 deletion includes/PostType/CollectionEntries.php
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,30 @@ private function collection_id_for_entry_post_type( string $post_type ): int {
return 0;
}

/**
* Returns a set of field meta keys that use multi-row post meta storage.
*
* @param string $post_type Entry post type.
* @return array<string,bool>
*/
private function multi_value_meta_keys_for_entry_post_type( string $post_type ): array {
$collection_id = $this->collection_id_for_entry_post_type( $post_type );
if ( $collection_id < 1 ) {
return array();
}

$keys = array();
foreach ( get_post_meta( $collection_id, 'fields', false ) as $field_id ) {
$field_id = (int) $field_id;
$type = (string) get_post_meta( $field_id, 'type', true );
if ( 'multiselect' === $type || ( 'relation' === $type && Relations::relation_is_multiple( $field_id ) ) ) {
$keys[ Relations::meta_key( $field_id ) ] = true;
}
}

return $keys;
}

/**
* Records the current user as the last editor of an entry.
*
Expand Down Expand Up @@ -508,11 +532,42 @@ public function register_for_collection( WP_Post $collection ): void {
}

if ( empty( self::$default_hooks[ $post_type ] ) ) {
add_filter( "rest_pre_insert_{$post_type}", array( $this, 'prepare_meta_for_defaults_before_rest_insert' ), 10, 2 );
add_action( "rest_after_insert_{$post_type}", array( $this, 'apply_defaults_after_rest_insert' ), 10, 3 );
self::$default_hooks[ $post_type ] = true;
}
}

/**
* Tracks explicit creation meta and removes empty multi-value fields before core REST deletes them.
*
* @param object $prepared_post Prepared post object.
* @param WP_REST_Request $request REST request.
*/
public function prepare_meta_for_defaults_before_rest_insert( object $prepared_post, WP_REST_Request $request ): object {
if ( ! empty( $prepared_post->ID ) || ! empty( $prepared_post->id ) ) {
return $prepared_post;
}

$meta = $request->get_param( 'meta' );
if ( ! is_array( $meta ) ) {
return $prepared_post;
}

$explicit_meta_keys = array_keys( $meta );
$multi_meta_keys = $this->multi_value_meta_keys_for_entry_post_type( (string) $prepared_post->post_type );
foreach ( $meta as $key => $value ) {
if ( array() === $value && isset( $multi_meta_keys[ (string) $key ] ) ) {
unset( $meta[ $key ] );
}
}

$request->set_param( 'meta', $meta );
$request->set_param( '_cortext_explicit_meta_keys', $explicit_meta_keys );

return $prepared_post;
}

public function apply_defaults_after_rest_insert( WP_Post $post, WP_REST_Request $request, bool $creating ): void {
if ( ! $creating ) {
return;
Expand All @@ -523,7 +578,13 @@ public function apply_defaults_after_rest_insert( WP_Post $post, WP_REST_Request
return;
}

FieldDefaults::apply_to_row( $collection_id, (int) $post->ID );
$explicit_meta_keys = $request->get_param( '_cortext_explicit_meta_keys' );
if ( ! is_array( $explicit_meta_keys ) ) {
$meta = $request->get_param( 'meta' );
$explicit_meta_keys = is_array( $meta ) ? array_keys( $meta ) : array();
}

FieldDefaults::apply_to_row( $collection_id, (int) $post->ID, $explicit_meta_keys );
}

public function assign_menu_order_on_insert( int $post_id, WP_Post $post, bool $update ): void {
Expand Down
41 changes: 41 additions & 0 deletions tests/php/test-rest-rows-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,47 @@ public function test_explicit_creation_meta_wins_over_field_default(): void {
$this->assertSame( 'Provided', get_post_meta( $row_id, "field-{$field_id}", true ) );
}

public function test_explicit_empty_multiselect_meta_wins_over_field_default(): void {
wp_set_current_user( $this->create_user( 'author' ) );
$collection_id = $this->create_collection_with_slug( 'Empty Multi Defaults', 'emptymultidefs' );
$field_id = $this->create_collection_field(
$collection_id,
'Tags',
'multiselect',
array(
'options' => wp_json_encode(
array(
array(
'value' => 'a',
'label' => 'A',
),
)
),
)
);
update_post_meta( $field_id, 'default_value', '{"mode":"value","value":["a"]}' );

$GLOBALS['wp_rest_server'] = new WP_REST_Server();
( new RowsController() )->register();
do_action( 'rest_api_init' );

$request = new WP_REST_Request( 'POST', '/wp/v2/crtxt_emptymultidefs' );
$request->set_body_params(
array(
'status' => 'private',
'title' => 'Empty tags row',
'meta' => array(
"field-{$field_id}" => array(),
),
)
);
$response = rest_do_request( $request );
$this->assertSame( 201, $response->get_status() );

$row_id = (int) $response->get_data()['id'];
$this->assertSame( array(), get_post_meta( $row_id, "field-{$field_id}", false ) );
}

public function test_query_rows_includes_collection_metadata(): void {
wp_set_current_user( $this->create_user( 'author' ) );
$fixture = $this->create_collection_fixture( 'rowmeta', 'text' );
Expand Down
Loading