Support

Account

Home Forums Backend Issues (wp-admin) How can I dynamically filter the choices in a taxonomy select? Reply To: How can I dynamically filter the choices in a taxonomy select?

  • Maybe some code from my current project will help. I don’t dynamically generate the content of the second field in php when the page is loaded. Since you’re familiar with my other examples.

    This is a cut down version of the JS file. I have 2 actions, one to initialize the sub category field and one when the category field changes. The init field basically just hides the sub category field if there is no selection in the category field. There is a line near the bottom where I trigger the init action when the page is loaded.

    
    jQuery(document).ready(function($) {
      if (typeof(acf) == 'undefined') {
        return;
      }
      var CMACF = acf.ajax.extend({
        events: {
          
          // initialize product sub category field
          'init [data-key="field_59dcc174f734c"] .acf-input select': 'init_product_sub_category',
          
          // change sub categories on category select
          'change [data-key="field_59dcc100f734b"] .acf-input select': 'change_product_category',
        }, // end events
        
        change_product_category: function(e) {
          var category = e.$el.val();
          
          //console.log(category);
          
          // clear current sub category
          $('[data-key="field_59dcc174f734c"] .acf-input select').val('');
          
          var action = 'get_product_sub_categories';
          
          var self = this;
          var data = this.o;
          
          data.action = 'cm_get_product_sub_categories';
          data.category = category;
          
          data.exists = [];
          
          this.request = $.ajax({
            url: acf.get('ajaxurl'),
            data: acf.prepare_for_ajax(data),
            type: 'post',
            dataType: 'json',
            success: function(json) {
              console.log(json);
              var $select = $('[data-key="field_59dcc174f734c"] .acf-input select');
              if (!json || json.length == 1) {
                // hide sub category select
                $select.closest('.acf-field').css('display', 'none');
                return;
              }
              // clear all selections from sub category select and replace with new values
              $select.empty();
              for (i=0; i<json.length; i++) {
                $select.append('<option value="'+json[i]['value']+'">'+json[i]['label']+'</option>');
              }
              // make sure the field is visible
              $select.closest('.acf-field').css('display', 'block');
            },
            error: function(jqXHR, textStatus, error) {
              console.log(jqXHR);
              console.log(textStatus);
              console.log(error);
            }
          }); // end request
          
        }, // end change_product_categoty
        
        init_product_sub_category: function(e) {
          // if catetory has a selection and that category has children show field
          // otherwise hide the field
          var category = $('[data-key="field_59dcc100f734b"] .acf-input select').val();
          //console.log(category);
          if (category == '') {
            e.$el.closest('.acf-field').css('display', 'none');
            e.$el.val('');
          }
          
          var action = 'get_product_sub_categories';
          
          var self = this;
          var data = this.o;
          
          data.action = 'cm_get_product_sub_categories';
          data.category = category;
          
          data.exists = [];
          
          this.request = $.ajax({
            url: acf.get('ajaxurl'),
            data: acf.prepare_for_ajax(data),
            type: 'post',
            dataType: 'json',
            success: function(json) {
              //console.log(json);
              if (!json || json.length == 1) {
                e.$el.closest('.acf-field').css('display', 'none');
                e.$el.val('');
                return;
              }
            },
            error: function(jqXHR, textStatus, error) {
              console.log(jqXHR);
              console.log(textStatus);
              console.log(error);
            }
          }); // end request
          
        }, // end init_product_sub_category
        
      });
      
      $('[data-key="field_59dcc174f734c"] .acf-input select').trigger('init');
      
    });
    

    This is the function that dynamically loads the choices of the sub category in php, as you can see by this, if nothing has been saved for the top level category field it returns and empty array for choices.

    
    function load_product_sub_category_field($field) {
      global $post;
      if ($post && isset($post->ID) && get_post_type($post->ID) == 'acf-field-group') {
        return $field;
      }
      $post_id = $post->ID;
      $category = intval(get_field('field_59dcc100f734b', $post_id));
      $choices = array();
      $terms = array();
      if ($category) {
        $args = array(
          'taxonomy' => 'product-category',
          'parent' => $category,
          'hide_empty' => false
        );
        $terms = get_terms($args);
      }
      if ($terms && !is_wp_error($terms)) {
        foreach ($terms as $term) {
          $choices[$term->term_id] = $term->name;
        }
      }
      $field['choices'] = $choices;
      return $field;
    }
    

    We can do this because when the post is saved ACF does not validate the value submitted for the field against the choices of the field. You’ll also notice that I don’t do this on the field group editor page. When I created this select field what I entered for choices is this will be dynamically generated. So choices are only added to this field if
    1) The post has already been saved and there is a value in the field this depends on
    OR
    2) When something is selected for the category and the field is dynamically populated using AJAX

    And finally, this is the function called in the AJAX request

    
    function get_product_sub_categories() {
      
      if (!wp_verify_nonce($_POST['nonce'], 'acf_nonce')) {
        echo json_encode(false);
        exit;
      }
      
      $check_fields = array(
        'category'
      );
      
      foreach ($check_fields as $index) {
        if (!isset($_POST[$index])) {
          echo json_encode(false);
          exit;
        }
      }
      
      $choices = array(array('value' => '', 'label' => '- Select -'));
      if (!$_POST['category']) {
        echo json_encode($choices);
        exit;
      }
      
      $args = array(
        'taxonomy' => 'product-category',
        'parent' => intval($_POST['category']),
        'hide_empty' => false
      );
      $terms = get_terms($args);
      
      if ($terms && !is_wp_error($terms)) {
        foreach ($terms as $term) {
          $choices[] = array('value' => $term->term_id, 'label' => $term->name);
        }
      }
      
      echo json_encode($choices);
      exit;
      
    }