Skip to content

Commit 417db1b

Browse files
kodinkatcorsacca
andauthored
API Update and Create, option to not overwrite existing values (#2668)
* Support new dt-import non-overwrite setting * Include overwrite logic within post update flows with supporting unit tests * Additional field type unit tests * Ensure unit test users are created accordingly * Introduce base_user * Rolled out base_user reference * moved function location * Fix field value comparison logic and improve option matching in Disciple_Tools_Posts class * Tweaked overwrite logic and unit test adjustments * delete extra filter * Updated dt_ignore_duplicated_post_fields logic and unit tests following revised requirements * Refactor unit tests to validate milestone handling and ensure user select fields are not overwritten during post creation * Enhance post handling by adding support for user_select, link, and connection fields; update unit tests to ensure fields are not overwritten during creation and updates * Addressed user does not have access to contacts unit test exceptions * revert Update install-wp-tests.sh * Fix endpoint parameter * use isset to check for value * Revert isset check, update on number fields * Fix duplicate detection for communication_channel fields with wrapped format The dt_ignore_duplicated_post_fields function now correctly handles both direct array format [['value' => 'xxx']] and wrapped format ['values' => [['value' => 'xxx']]] for communication_channel fields. - Added logic to detect if field_value has a 'values' key and extract the correct array to iterate over - Preserves the original format (wrapped or direct) when returning updated fields - Fixes bug where wrapped format was not being processed correctly, leading to incorrect duplicate detection This ensures that duplicate detection works consistently regardless of the field format received. * location and boolean fields * fixed the deprecated str_getcsv() function calls * Standardize field format handling: Always return wrapped format All multi-value field types (tags, link, connection, multi_select, location, location_meta, communication_channel) now consistently: - Accept both direct array format [['value' => 'xxx']] and wrapped format ['values' => [['value' => 'xxx']]] - Always return wrapped format ['values' => ] for consistency This ensures uniform behavior across all field types and eliminates format inconsistencies that could cause issues when fields are provided in different formats. * Update unit tests to standardize contact_phone and contact_email field formats Modified the unit tests for create and update post functionalities to use the new wrapped format for contact_phone and contact_email fields. This change ensures consistency with the recent updates to field handling across the codebase. --------- Co-authored-by: corsac <corsacca@gmail.com>
1 parent b9a5aa0 commit 417db1b

6 files changed

Lines changed: 993 additions & 7 deletions

File tree

dt-mapping/migrations/0006-add-grid-to-db.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public function up() {
5353
$line = fgets( $fp, 2048 );
5454
$count++;
5555

56-
$data = str_getcsv( $line, "\t" );
56+
$data = str_getcsv( $line, "\t", '"', '\\' );
5757

5858
$data_sql = dt_array_to_sql( $data );
5959

dt-posts/dt-posts-endpoints.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -589,9 +589,11 @@ public function create_post( WP_REST_Request $request ) {
589589
$url_params = $request->get_url_params();
590590
$get_params = $request->get_query_params();
591591
$silent = isset( $get_params['silent'] ) && $get_params['silent'] === 'true';
592-
$check_dups = ! empty( $get_params['check_for_duplicates'] ) ? explode( ',', $get_params['check_for_duplicates'] ) : [];
592+
$check_dups = !empty( $get_params['check_for_duplicates'] ) ? explode( ',', $get_params['check_for_duplicates'] ) : [];
593+
$do_not_overwrite_existing_fields = !empty( $get_params['do_not_overwrite_existing_fields'] );
593594
$post = DT_Posts::create_post( $url_params['post_type'], $fields, $silent, true, [
594-
'check_for_duplicates' => $check_dups
595+
'check_for_duplicates' => $check_dups,
596+
'do_not_overwrite_existing_fields' => $do_not_overwrite_existing_fields
595597
] );
596598
return $post;
597599
}
@@ -607,7 +609,10 @@ public function update_post( WP_REST_Request $request ){
607609
$url_params = $request->get_url_params();
608610
$get_params = $request->get_query_params();
609611
$silent = isset( $get_params['silent'] ) && $get_params['silent'] === 'true';
610-
return DT_Posts::update_post( $url_params['post_type'], $url_params['id'], $fields, $silent );
612+
$do_not_overwrite_existing_fields = !empty( $get_params['do_not_overwrite_existing_fields'] );
613+
return DT_Posts::update_post( $url_params['post_type'], $url_params['id'], $fields, $silent, true, [
614+
'do_not_overwrite_existing_fields' => $do_not_overwrite_existing_fields
615+
] );
611616
}
612617

613618
public function delete_post( WP_REST_Request $request ){

dt-posts/dt-posts.php

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,15 +84,16 @@ public static function create_post( string $post_type, array $fields, bool $sile
8484
if ( isset( $args['check_for_duplicates'] ) && is_array( $args['check_for_duplicates'] ) && ! empty( $args['check_for_duplicates'] ) ) {
8585
$duplicate_post_ids = apply_filters( 'dt_create_check_for_duplicate_posts', [], $post_type, $fields, $args['check_for_duplicates'], $check_permissions );
8686
if ( ! empty( $duplicate_post_ids ) && count( $duplicate_post_ids ) > 0 ) {
87+
$duplicate_post_id = $duplicate_post_ids[0];
8788

8889
$name = $fields['name'] ?? $fields['title'];
8990

9091
$fields['notes'] = isset( $fields['notes'] ) ? $fields['notes'] : [];
9192
//No need to update title or name.
92-
unset( $fields['title'], $fields['name'] );
93+
unset( $fields['title'], $fields['name'], $fields['ID'] );
9394

9495
//update most recently created matched post.
95-
$updated_post = self::update_post( $post_type, $duplicate_post_ids[0], $fields, $silent, false );
96+
$updated_post = self::update_post( $post_type, $duplicate_post_id, $fields, $silent, false, $args );
9697
if ( is_wp_error( $updated_post ) ){
9798
return $updated_post;
9899
}
@@ -391,7 +392,7 @@ public static function create_post( string $post_type, array $fields, bool $sile
391392
*
392393
* @return array|WP_Error
393394
*/
394-
public static function update_post( string $post_type, int $post_id, array $fields, bool $silent = false, bool $check_permissions = true ){
395+
public static function update_post( string $post_type, int $post_id, array $fields, bool $silent = false, bool $check_permissions = true, $args = [] ){
395396
$post_types = self::get_post_types();
396397
if ( !in_array( $post_type, $post_types ) ){
397398
return new WP_Error( __FUNCTION__, 'Post type does not exist', [ 'status' => 403 ] );
@@ -415,6 +416,15 @@ public static function update_post( string $post_type, int $post_id, array $fiel
415416
return new WP_Error( __FUNCTION__, 'post does not exist', [ 'status' => 404 ] );
416417
}
417418

419+
/**
420+
* If field overwrite has been disabled for existing fields, then ensure
421+
* to have them removed from importing fields.
422+
*/
423+
424+
if ( isset( $args['do_not_overwrite_existing_fields'] ) && $args['do_not_overwrite_existing_fields'] ) {
425+
$fields = self::dt_ignore_duplicated_post_fields( $fields, $post_type, $post_id );
426+
}
427+
418428
$existing_post = self::get_post( $post_type, $post_id, false, false );
419429
//get extra fields and defaults
420430
$fields = apply_filters( 'dt_post_update_fields', $fields, $post_type, $post_id, $existing_post );

dt-posts/posts.php

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3159,6 +3159,122 @@ public static function geolocate_addresses( $post_id, $post_type, $field_key, $a
31593159

31603160
return false;
31613161
}
3162+
3163+
3164+
/**
3165+
* Remove duplicated field values from specified post record.
3166+
*
3167+
* @param $fields
3168+
* @param $post_type
3169+
* @param $post_id
3170+
* @return array
3171+
*/
3172+
public static function dt_ignore_duplicated_post_fields( $fields, $post_type, $post_id ) {
3173+
$updated_fields = [];
3174+
$existing_fields = DT_Posts::get_post( $post_type, $post_id, true, false );
3175+
if ( empty( $existing_fields ) || is_wp_error( $existing_fields ) ){
3176+
return $fields;
3177+
}
3178+
$field_settings = DT_Posts::get_post_field_settings( $post_type );
3179+
foreach ( $fields as $field_key => $field_value ) {
3180+
if ( !isset( $existing_fields[ $field_key ], $field_settings[ $field_key ]['type'] ) ){
3181+
$updated_fields[ $field_key ] = $field_value;
3182+
continue;
3183+
}
3184+
3185+
$field_type = $field_settings[ $field_key ]['type'];
3186+
switch ( $field_type ) {
3187+
case 'text':
3188+
case 'textarea':
3189+
case 'number':
3190+
case 'boolean':
3191+
case 'date':
3192+
case 'key_select':
3193+
case 'user_select':
3194+
if ( empty( $existing_fields[ $field_key ] ) ) {
3195+
$updated_fields[ $field_key ] = $field_value;
3196+
}
3197+
break;
3198+
case 'tags':
3199+
case 'link':
3200+
case 'connection':
3201+
case 'multi_select':
3202+
$values = [];
3203+
// Handle both direct array format [['value' => 'xxx']] and wrapped format ['values' => [['value' => 'xxx']]]
3204+
$field_values = isset( $field_value['values'] ) ? $field_value['values'] : ( $field_value ?? [] );
3205+
3206+
foreach ( $field_values as $value ) {
3207+
if ( isset( $value['delete'] ) || !( isset( $value['value'] ) && in_array( $value['value'], $existing_fields[ $field_key ] ) ) ) {
3208+
$values[] = $value;
3209+
}
3210+
}
3211+
if ( !empty( $values ) ) {
3212+
$updated_fields[ $field_key ] = [ 'values' => $values ];
3213+
}
3214+
break;
3215+
case 'location':
3216+
case 'location_meta':
3217+
$values = [];
3218+
// Handle both direct array format [['value' => 'xxx']] and wrapped format ['values' => [['value' => 'xxx']]]
3219+
$field_values = isset( $field_value['values'] ) ? $field_value['values'] : ( $field_value ?? [] );
3220+
3221+
foreach ( $field_values as $value ) {
3222+
$key = 'label';
3223+
$found = array_filter( $existing_fields[ $field_key ], function ( $option ) use ( $value, $key ) {
3224+
$hit = isset( $option[$key], $value[$key] ) && $option[$key] == $value[$key];
3225+
3226+
if ( isset( $value['delete'] ) ) {
3227+
$hit = false;
3228+
} elseif ( !$hit && isset( $option['matched_search'], $value[$key] ) && $option['matched_search'] == $value[$key] ) {
3229+
$hit = true;
3230+
} elseif ( !$hit && isset( $option['id'], $value['value'] ) && $option['id'] == $value['value'] ) {
3231+
$hit = true;
3232+
}
3233+
3234+
return $hit;
3235+
} );
3236+
if ( empty( $found ) || count( $found ) == 0 ) {
3237+
$values[] = $value;
3238+
}
3239+
}
3240+
if ( !empty( $values ) ) {
3241+
$updated_fields[ $field_key ] = [ 'values' => $values ];
3242+
}
3243+
break;
3244+
case 'communication_channel':
3245+
$values = [];
3246+
$existing_field_values = $existing_fields[ $field_key ];
3247+
3248+
// Handle both direct array format [['value' => 'xxx']] and wrapped format ['values' => [['value' => 'xxx']]]
3249+
$field_values = isset( $field_value['values'] ) ? $field_value['values'] : ( $field_value ?? [] );
3250+
3251+
foreach ( $field_values as $value ) {
3252+
$hit = false;
3253+
if ( !isset( $value['delete'] ) && isset( $value['value'] ) ) {
3254+
$found = array_filter( $existing_field_values, function ( $existing_field ) use ( $value ) {
3255+
return isset( $existing_field['value'] ) && $value['value'] == $existing_field['value'];
3256+
} );
3257+
3258+
$hit = !empty( $found );
3259+
}
3260+
3261+
if ( !$hit ) {
3262+
$values[] = $value;
3263+
}
3264+
}
3265+
3266+
if ( !empty( $values ) ) {
3267+
$updated_fields[ $field_key ] = [ 'values' => $values ];
3268+
}
3269+
break;
3270+
default:
3271+
$updated_fields[ $field_key ] = $field_value;
3272+
break;
3273+
}
3274+
}
3275+
3276+
return $updated_fields;
3277+
}
31623278
}
31633279

31643280
/**

0 commit comments

Comments
 (0)