• Resolved Lionel Pointet

    (@lpointet)


    Hello,

    Thanks for your work on this plugin.
    I saw this could be a related ticket: https://ww.wp.xz.cn/support/topic/import-user-meta-acf/

    Actually, I have an ACF field configured as “select” type but with “multiple” option being false. This ensures we can only select a single value from the list, and it’s stored as a string, not as an (serialized) array in the DB.

    Unfortunately, when I add a value in a column and import that, it is stored as an array with a single value, serialized.

    I can see this is due to ACUI_ACF::import method only checking if the field type is “select” to determine if this is a “multiple” field type. It would be great if it also checked the “multiple” configuration inside this field.

    Don’t hesitate if you need further information, or even an updated code from ACUI_ACF class for this particular case.

    Best regards.

Viewing 5 replies - 1 through 5 (of 5 total)
  • Plugin Author Javier Carazo

    (@carazo)

    @lpointet,

    This would be great:

    an updated code from ACUI_ACF class for this particular case

    Or tell me how we can reproduce the problem and we will fix it.

    Thread Starter Lionel Pointet

    (@lpointet)

    Hello @carazo,

    Thanks for your quick reply. Since I cannot upload any file here, I will paste the code directly.
    The corresponding git patch:

    From dc1f839aa1ca913ad5455af07a26ea4b12181d85 Mon Sep 17 00:00:00 2001
    From: Lionel Pointet <[email protected]>
    Date: Wed, 10 Mar 2021 08:38:22 +0100
    Subject: [PATCH] Fix ACUI_ACF class for multiple select ACF fields
    
    ---
     .../addons/advanced-custom-fields.php               | 13 +++++++++----
     1 file changed, 9 insertions(+), 4 deletions(-)
    
    diff --git a/wp-content/plugins/import-users-from-csv-with-meta/addons/advanced-custom-fields.php b/wp-content/plugins/import-users-from-csv-with-meta/addons/advanced-custom-fields.php
    index 4bd0272..e02af36 100644
    --- a/wp-content/plugins/import-users-from-csv-with-meta/addons/advanced-custom-fields.php
    +++ b/wp-content/plugins/import-users-from-csv-with-meta/addons/advanced-custom-fields.php
    @@ -43,7 +43,6 @@ class ACUI_ACF{
     	function import( $headers, $row, $user_id ){
     		$fields_positions = array();
     		$types = $this->get_user_fields_types();
    -		$types_multiple = array( 'select', 'checkbox', 'radio', 'button_group' );
     
     		foreach ( $types as $key => $type ) {
     			$pos = array_search( $key, $headers );
    @@ -62,14 +61,14 @@ class ACUI_ACF{
     			}*/
     
     			// slugs in relationship
    -			if( $types[ $key ] == 'relationship' && (string)(int)$data[0] != $data[0] ){
    +			if( $types[ $key ][ 'type' ] == 'relationship' && (string)(int)$data[0] != $data[0] ){ // @todo $data is undefined here, maybe $row was meant instead?
     				$data = explode( ',', $row[ $pos ] );
     
     				foreach ( $data as $it => $slug ) {
     					$data[ $it ] = $this->get_post_id_by_slug( $slug );
     				}
     			}
    -			elseif( in_array( $types[ $key ], $types_multiple ) ){
    +			elseif( $types[ $key ][ 'multiple' ] ){
     				$data = explode( ',', $row[ $pos ] );
     				array_filter( $data, function( $value ){ return $value !== ''; } );
     			}
    @@ -123,13 +122,18 @@ class ACUI_ACF{
     	function get_user_fields_types(){
     		$fields = $this->get_user_fields();
     		$fields_keys = array();
    +		$types_multiple = array( 'select', 'checkbox', 'radio', 'button_group' );
     
     		if( empty( $fields ) )
     			return array();
     
     		foreach ( $fields as $group => $fields_of_group ){
     			foreach ( $fields_of_group as $field ){
    -				$fields_keys[ $field['name'] ] = $field['type'];
    +				$fields_keys[ $field['name'] ] = [
    +					'type' => $field['type'],
    +					// 'select' type has a 'multiple' key which can be 0 or 1
    +					'multiple' => !empty( $field['multiple'] ) || ( !isset( $field['multiple'] ) && in_array( $field['type'], $types_multiple ) ),
    +				];
     			}
     		}
     
    @@ -172,6 +176,7 @@ class ACUI_ACF{
     
     				if ( 0 == $p->post_parent && count( $revparts ) == $count + 1 && $p->post_name == $revparts[ $count ] ) {
     					$foundid = $page->ID;
    +					// @todo $post_type is undefined here
     					if ( $page->post_type == $post_type ) {
     						break;
     					}
    -- 
    2.28.0.windows.1

    And the complete file:

    <?php
    
    if ( ! defined( 'ABSPATH' ) ) exit; 
    
    if( !is_plugin_active( 'advanced-custom-fields-pro/acf.php' ) && !is_plugin_active( 'advanced-custom-fields/acf.php' ) ){
    	return;
    }
    
    class ACUI_ACF{
    	function __construct(){
    		add_filter( 'acui_restricted_fields', array( $this, 'restricted_fields' ), 10, 1 );
    		add_filter( 'acui_not_meta_fields', array( $this, 'restricted_fields' ), 10, 1 );
    		add_action( 'acui_documentation_after_plugins_activated', array( $this, 'documentation' ) );
    		add_action( 'post_acui_import_single_user', array( $this, 'import' ), 10, 3 );		
    	}
    
    	function restricted_fields( $acui_restricted_fields ){
    		return array_merge( $acui_restricted_fields, $this->get_user_fields_keys() );
    	}
    
    	function documentation(){
    		$fields = $this->get_user_fields();
    		?>
    		<tr valign="top">
    			<th scope="row"><?php _e( "Advaced Custom Fields is activated", 'import-users-from-csv-with-meta' ); ?></th>
    			<td>
    				<?php _e( "You can import those fields, look at every group which fields you can import using the column names shown below.", 'import-users-from-csv-with-meta' ); ?>.
    				<ul style="list-style:disc outside none; margin-left:2em;">
    				<?php foreach ( $this->get_user_fields() as $group => $fields ): ?>
    					<li><?php _e( "Group name", 'import-users-from-csv-with-meta' ); ?>: <em><?php echo $group; ?></em></li>
    					<ul style="list-style:square inside none; margin-left:2em;">
    						<?php foreach ( $fields as $field ): ?>
    						<li><?php echo $field['label']; ?> <em>(type: <?php echo $field['type']; ?>)</em> - Column name in the CSV: <strong><?php echo $field['name']; ?></strong></li>
    						<?php endforeach; ?>
    					</ul>
    				<?php endforeach; ?>
    				</ul>
    			</td>
    		</tr>
    		<?php
    	}
    
    	function import( $headers, $row, $user_id ){
    		$fields_positions = array();
    		$types = $this->get_user_fields_types();
    
    		foreach ( $types as $key => $type ) {
    			$pos = array_search( $key, $headers );
    
    			if( $pos === FALSE )
    				continue;
    
    			$fields_positions[ $pos ] = $key;
    		}
    
    		foreach ( $fields_positions as $pos => $key ) {
    			/*$preexisting_values = get_field( $key, "user_" . $user_id );
    			if( !empty( $preexisting_values ) ){
    				$data = array_unique( array_merge( $preexisting_values, $data ) );
    				$data = array_filter( $data, function( $value ) { return !is_null( $value ) && $value !== '' && $value != 0; } );
    			}*/
    
    			// slugs in relationship
    			if( $types[ $key ][ 'type' ] == 'relationship' && (string)(int)$data[0] != $data[0] ){ // @todo $data is undefined here, maybe $row was meant instead?
    				$data = explode( ',', $row[ $pos ] );
    
    				foreach ( $data as $it => $slug ) {
    					$data[ $it ] = $this->get_post_id_by_slug( $slug );
    				}
    			}
    			elseif( $types[ $key ][ 'multiple' ] ){
    				$data = explode( ',', $row[ $pos ] );
    				array_filter( $data, function( $value ){ return $value !== ''; } );
    			}
    			else{
    				$data = $row[ $pos ];
    			}
    			
    			update_field( $key, $data, "user_" . $user_id );
    		}
    	}
    
    	function get_user_fields(){
    		$post_id = "user_new";
    		$fields = array();
    		
    		$args = array(
    			'user_id'	=> 'new',
    			'user_form'	=> '#your-profile'
    		);
    		
    		$field_groups = acf_get_field_groups( array( 'user_id' => 'new', 'user_form' => '#your-profile' ) );
    		
    		if( empty($field_groups) ) 
    			return;
    		
    		acf_form_data( array( 'post_id'	=> "user_new", 'nonce' => 'user' ) );
    		
    		foreach( $field_groups as $field_group ) {
    			$fields[ $field_group['title'] ] = acf_get_fields( $field_group );
    		}
    
    		return $fields;
    	}
    
    	function get_user_fields_keys(){
    		$fields = $this->get_user_fields();
    		$fields_keys = array();
    
    		if( empty( $fields ) )
    			return array();
    
    		foreach ( $fields as $group => $fields_of_group ){
    			foreach ( $fields_of_group as $field ){
    				$fields_keys[] = $field['name'];
    			}
    		}
    
    		return $fields_keys;
    	}
    
    	function get_user_fields_types(){
    		$fields = $this->get_user_fields();
    		$fields_keys = array();
    		$types_multiple = array( 'select', 'checkbox', 'radio', 'button_group' );
    
    		if( empty( $fields ) )
    			return array();
    
    		foreach ( $fields as $group => $fields_of_group ){
    			foreach ( $fields_of_group as $field ){
    				$fields_keys[ $field['name'] ] = [
    					'type' => $field['type'],
    					// 'select' type has a 'multiple' key which can be 0 or 1
    					'multiple' => !empty( $field['multiple'] ) || ( !isset( $field['multiple'] ) && in_array( $field['type'], $types_multiple ) ),
    				];
    			}
    		}
    
    		return $fields_keys;
    	}
    
    	function get_post_id_by_slug( $slug ){
    		global $wpdb;
    
    		$page_path     = rawurlencode( urldecode( $slug ) );
    		$page_path     = str_replace( '%2F', '/', $page_path );
    		$page_path     = str_replace( '%20', ' ', $page_path );
    		$parts         = explode( '/', trim( $page_path, '/' ) );
    		$parts         = array_map( 'sanitize_title_for_query', $parts );
    		$escaped_parts = esc_sql( $parts );
    
    		$in_string = "'" . implode( "','", $escaped_parts ) . "'";
    
    		$sql = "SELECT ID, post_name, post_parent, post_type FROM $wpdb->posts WHERE post_name IN ($in_string)";
    
    		$pages = $wpdb->get_results( $sql, OBJECT_K );
    
    		$revparts = array_reverse( $parts );
    
    		$foundid = 0;
    
    		foreach ( (array) $pages as $page ) {
    			if ( $page->post_name == $revparts[0] ) {
    				$count = 0;
    				$p     = $page;
    
    				while ( 0 != $p->post_parent && isset( $pages[ $p->post_parent ] ) ) {
    					$count++;
    					$parent = $pages[ $p->post_parent ];
    					if ( ! isset( $revparts[ $count ] ) || $parent->post_name != $revparts[ $count ] ) {
    						break;
    					}
    					$p = $parent;
    				}
    
    				if ( 0 == $p->post_parent && count( $revparts ) == $count + 1 && $p->post_name == $revparts[ $count ] ) {
    					$foundid = $page->ID;
    					// @todo $post_type is undefined here
    					if ( $page->post_type == $post_type ) {
    						break;
    					}
    				}
    			}
    		}
    
    		return $foundid;
    	}
    }
    
    new ACUI_ACF();

    FYI, I added 2 “@todo” comments in places where some variables are undefined, I’m not sure what were the use cases and it was not part of mine anyway.

    I’m using a workaround before you fix this issue by filtering the value before ACF updates the value:

    /**
     * Ensure we import correctly data from ACF field groups.
     * Import users and customers with meta plugin incorrectly stores serialized arrays for non-multiple select field type values.
     *
     * @param mixed $value
     * @param string|int $post_id
     * @param array $field
     *
     * @return mixed
     */
    function multiple_select_acf_values( $value, $post_id, $field ) {
        if( 'select' === $field['type'] && !$field['multiple'] && is_array( $value ) ) {
            $value = array_shift( $value );
        }
    
        return $value;
    }
    add_filter( 'acf/update_value', 'multiple_select_acf_values', 10, 3 );

    Don’t hesitate to contact me if you need.

    Plugin Author Javier Carazo

    (@carazo)

    Thanks for your help! You are great.

    Respect to todos:
    1) data seems to be useful when I used preexisting value, now it seems it is not useful
    2) $post_type would need to be $p->post_type (anyway I have moved this function to the class where it should be).

    I have just included it and I am going to make the update.

    Please check and tell me if all works as it should.

    Thread Starter Lionel Pointet

    (@lpointet)

    Hi,

    Thank you for this update. It works as expected!

    I can see the “get_post_id_by_slug” method has been moved but its call from ACUI_ACF class hasn’t been updated though.
    I guess $this->get_post_id_by_slug( $slug ); should be ACUI_Helper::get_post_id_by_slug( $slug ); on line 68.

    Thanks anyway for your prompt responses.

    Plugin Author Javier Carazo

    (@carazo)

    Yes I know, I did not change all the trunk.

    Sorry, I will include in next version. We are so busy that sometimes we do not take care enough.

Viewing 5 replies - 1 through 5 (of 5 total)

The topic ‘ACF multiple select field type’ is closed to new replies.