Advanced custom fields / populate select based on another acf field Advanced custom fields / populate select based on another acf field wordpress wordpress

Advanced custom fields / populate select based on another acf field


I know this question is a bit old but it has a few upvotes so I thought it would be worth posting an answer for this problem.

When you edit a 'lease' post, set the manufacturer then populate the model field from its value with AJAX, the models select box is populated with values for the chosen manufacturer. This value isn't validated server-side as a 'valid' choice, so it is saved in your database as post meta correctly.

On loading the edit screen again, the current value for model is not selected because when Advanced Custom Fields generates the HTML for a select field server-side, there are no choices to be pre-selected. The following PHP walker from fields/select.php is passed the fields $choices and $values for the field/post being edited:

function walk( $choices, $values ) {    // bail ealry if no choices    if( empty($choices) ) return;    // loop    foreach( $choices as $k => $v ) {        // optgroup        if( is_array($v) ){            // optgroup            echo '<optgroup label="' . esc_attr($k) . '">';            // walk            $this->walk( $v, $values );            // close optgroup            echo '</optgroup>';            // break            continue;        }        // vars        $search = html_entity_decode($k);        $pos = array_search($search, $values);        $atts = array( 'value' => $k );        // validate selected        if( $pos !== false ) {            $atts['selected'] = 'selected';            $atts['data-i'] = $pos;        }        // option        echo '<option ' . acf_esc_attr($atts) . '>' . $v . '</option>';    }}

As your field has no choices until AJAX uses the manufacturer field to populate them, the selected attribute isn't set. You should populate choices for the model field server-side too to retain the value on post edit screen after saving. For example:

function load_current_models($field){  /** Get posts current manufacturer */  $current_manufact = get_field('manufacturer');  /** Manufacturer must be set */  if($current_manufact) {    /** Get manufacturers and models from options page */    $all_models = get_field('car_m_and_m', 'options');    /** Look for manufacturers models **/    foreach($all_models as $manufacturer){      if($manufacturer['manufacturer'] == $current_manufact){        $field['choices'] = explode(', ', $model['models']);        return $field;      }     }  }  /** Disable models by default */  $field['disabled'] = true;  return $field;}add_filter('acf/load_field/key=field_5548da7058203', 'load_current_models');

This will also disable the model field on load if the manufacturer hasn't been set, I assume a new post, allowing you to remove the .change() call from your JS which is causing the manufacturer select changed event to be triggered on load too. This would append duplicate model options after those passed server-side otherwise.

You should update the JS to remove the 'old' options too on manufacturer change else if you selected a manufacturer then changed it to another, both manufacturers models would be included in the options. For example:

// Get models field jQuery objectvar models = $('#acf-field_5548da7058203');// Disable while waiting for servermodels.prop('disabled', true);// Remove old model field optionsmodels.find('option').each(function(){  if($(this).val() != 0) $(this).remove();});// Get response and populate models select field$.post( ajaxurl, data, function(response) {  if( response ){    // Add models to select field options    $.each(response, function(val, text) {      models.append( $('<option></option>').val(text).html(text) );    });    // Enable 'Select Model' field    models.removeAttr( 'disabled' );  }});