Support

Account

Home Forums Backend Issues (wp-admin) How to dynamically remove choices from select field?

Solved

How to dynamically remove choices from select field?

  • Hi there. I have a select field attached to a certain post type in my installation and I’m looking to remove some choices if they’ve already been chosen. Something like – if my_field has a value of location-1 in a published post “My Event”, the choice location-1 won’t show up in my_field when I’m adding/editing another post.

    My rough attempt looked something like this – but it won’t work.

    	$selector = get_field_object('field_59772109bf9d4');
    	global $oldchoices;
    	$oldchoices = $selector['choices'];
    
    	function acf_load_ad_zones_choices( $field ) {
    
    		// $choiceArray is an array of all possible ad zone values
    		// we'll be using it to compare against ad zones in use in published ads
    		$choiceArray = [];
    
    		foreach ($oldchoices as $oldchoice) {
    			array_push($choiceArray, $oldchoice);
    		}
    
    		// get all ads and put ad zones attached to them into an array
    		$args = array(
    			'post_type' => 'rsc-ads',
    			'posts_per_page' => -1,
    			'post_status' => 'publish'
    		); 
    		$ads = get_posts( $args );
    
    		// array of values already in use
    		// will be populated with all zones used by published ads
    		$choicevalues = [];
    
    		foreach ($ads as $ad) {
    			// get ad_zones values from the ad
    			$advalues = get_field('ad_zones', $ad->ID);
    
    			// put all the ad_zone values into an array
    			foreach ($advalues as $key => $value) {
    				array_push($choicevalues, $value);
    			}
    		}
    
    		// reset choices 
    		$field['choices'] = array();
    
    		$result = array_diff($choiceArray, $choicevalues);
    
    		 // loop through array and add to field 'choices'
    	    if ( is_array($result) ) {
    	        foreach( $result as $choice ) {
    	            $field['choices'][ $choice ] = $choice;
    	        }
    	    }
    	    
    	    // return the field
    	    return $field;
    
    	}
    
    	add_filter('acf/load_field/key=field_59772109bf9d4', 'acf_load_ad_zones_choices');

    $result is correct in that it contains only the options not selected in any of my published posts but replacing default choices with that array doesn’t work – the field still shows all the options. Any ideas?

  • One observation is that the first 3 lines of the code you posted should be inside of the function.

    You said this is a select field? Is that the ACF field type or is the field actually a relationship or maybe a post object field?

  • First off – sorry, I accidentally marked this as solved and apparently there’s no way to unmark it? Still not solved for me, apologies!

    When I put the first 3 lines I posted inside of my function, it turns the whole function into an unending loop and the custom fields don’t load on my page at all.

    Let me know if I can make myself clearer – I know this problem is a bit confusing.

  • I don’t think there is a way to mark unmark a solution.

    The reason it becomes an infinite loop is that you’re loading the field inside of the filter that loads the field so your filter keeps getting called. You don’t really need to get the field to get the current choices because they are already passed as part of $field

    
    function acf_load_ad_zones_choices( $field ) {
      
      $choiceArray = $field['choices'];
    
      // get all ads and put ad zones attached to them into an array
      $args = array(
        'post_type' => 'rsc-ads',
        'posts_per_page' => -1,
        'post_status' => 'publish'
      ); 
      $ads = get_posts( $args );
    
      // array of values already in use
      // will be populated with all zones used by published ads
      $choicevalues = array();
    
      foreach ($ads as $ad) {
        // get ad_zones values from the ad
        $advalues = get_field('ad_zones', $ad->ID);
    
        // put all the ad_zone values into an array
        foreach ($advalues as $key => $value) {
          array_push($choicevalues, $value);
        }
      }
    
      // reset choices 
      $field['choices'] = array();
    
      $result = array_diff($choiceArray, $choicevalues);
    
    /* 
      I don't really think you need to clear choices and then do the loop
      but I can't tell for sure looking at your code. I think you can delete
      this line above $field['choices'] = array();
      and just do $field['choices'] = $results;
      and then delete the following loop
    */
    
       // loop through array and add to field 'choices'
        
        if ( is_array($result) ) {
            foreach( $result as $choice ) {
                $field['choices'][ $choice ] = $choice;
            }
        }
        
        // return the field
        return $field;
    
    }
    
    add_filter('acf/load_field/key=field_59772109bf9d4', 'acf_load_ad_zones_choices');
    
    
  • Still getting the same result, both with just using $field['choices'] = $result; and the foreach loop:

    Fatal error: Allowed memory size of 268435456 bytes exhausted (tried to allocate 262144 bytes) in (…)/wp-includes/class-wp-query.php on line 889

  • I’ve done some more testing and it seems that it all hangs on this:

      foreach ($ads as $ad) {
        // get ad_zones values from the ad
        $advalues = get_field('ad_zones', $ad->ID);
      }

    As soon as I try to get_field() inside my loop, it times out. I also tried using WP_Query instead of get_posts, with the same result. There are 2 posts that are being looped through so it definitely shouldn’t do this…

    However, if I test it outside of the acf/load_field filter (getting the posts and their custom fields values and comparing them against all choices) – it works fine. It only times out when put inside the filter function.

    This is why I initially put it outside of the filter function – it’s queueing the same field as the filter is loading (ad_zones is the field I’m trying to filter).

  • are ad_zones and field_59772109bf9d4 the same field? If they are then this is creating the infinite loop. You need to remove the filter at the beginning and add it again at the end so that the filter does not run when getting values from itself in other instances.

    
    function acf_load_ad_zones_choices( $field ) {
      remove_filter(acf/load_field/key=field_59772109bf9d4', 'acf_load_ad_zones_choices');
      
      // the rest of your function
      
      add_filter('acf/load_field/key=field_59772109bf9d4', 'acf_load_ad_zones_choices');
      
      return $field;
    } 
    
Viewing 7 posts - 1 through 7 (of 7 total)

The topic ‘How to dynamically remove choices from select field?’ is closed to new replies.