Support

Account

Home Forums Backend Issues (wp-admin) Custom Location Rule for Custom Taxonomy

Solving

Custom Location Rule for Custom Taxonomy

  • I’m working on creating a custom location rule by following this tutorial. This involves using a custom taxonomy (though register_taxonomy) on a custom post type.

    My goal is to show certain custom fields only if a specific category is chosen on a custom post type. This is exactly like the pre-built location rule for “Post Category is equal to blank“, I just need to make it work for a different taxonomy on my custom post type.

    This is the code I used to register my custom taxonomy:

    register_taxonomy(
       'fr_product_categories',
       'fr_product',
       array(
          'label' => __( 'Product Categories' ),
          'rewrite' => array( 'slug' => 'product-category' ),
          'hierarchical' => true,
          'show_ui' => false,
       )
    );

    Below is the code built into ACF that allows you to make rules based on Post Category. I have tried everything I can think of to convert this from the standard post category to my custom taxonomy, but I cannot seem to get it working. Any advice on what areas I need to change in order to get this functional? Thanks in advance!

    function acf_location_rules_match_product_category($match, $rule, $options){
    	// validate
    	if(!$options['post_id']){return false;}
    	// find post type if it wasnt set already
    	if(!$options['post_type']){$options['post_type'] = get_post_type($options['post_id']);}
    	
    	// vars
    	$taxonomies = get_object_taxonomies($options['post_type']);
    	$terms = $options['post_category'];
    		
    	// not AJAX 
    	//if(!$options['ajax']){
    		// no terms? Load them from the post_id
    		if(empty($terms)){
    			$all_terms = get_the_terms($options['post_id'], 'category');
    			if($all_terms){
    				foreach($all_terms as $all_term) {
    					$terms[] = $all_term->term_id;
    				}
    			}
    		}	
    	
    		// no terms at all? 
    		if(empty($terms)){
    			// If no terms, this is a new post and should be treated as if it has the "Uncategorized" (1) category ticked
    			if(is_array($taxonomies) && in_array('category', $taxonomies)){
    				$terms[] = '1';
    			}
    		}
    	//}
    	if($terms){
    		if($rule['operator'] == "==") {
    			if(in_array($rule['value'], $terms)){
    				return true;
    			}
    		}
    		elseif($rule['operator'] == "!=") {
    			if(in_array($rule['value'], $terms)){
    				return false;
    			}
    		}
    	}
    	//fail-safe, should never be reached unless an unknown operator is selected or there are no terms still
    	return false;
    }
  • Hi @brettzie

    I believe you can do it by using the get_terms() function to make it simpler. Maybe something like this:

    add_filter('acf/location/rule_types', 'acf_location_rules_types_product');
    
    function acf_location_rules_types_product( $choices ) {
        
        $choices['Post']['product_tax'] = 'Product Tax';
    
        return $choices;
        
    }
    
    add_filter('acf/location/rule_values/product_tax', 'acf_location_rules_values_product');
    
    function acf_location_rules_values_product( $choices ) {
        
        $terms = get_terms( array(
            'taxonomy' => 'fr_product_categories',
            'hide_empty' => false,
        ) );
    
        if( $terms ) {
            
            foreach( $terms as $term ) {
                
                $choices[ $term->term_id ] = $term->name;
                
            }
            
        }
    
        return $choices;
    }
    
    add_filter('acf/location/rule_match/product_tax', 'acf_location_rules_match_product_category', 10, 3);
    
    function acf_location_rules_match_product_category($match, $rule, $options){
        // validate
        if(!$options['post_id']){return false;}
        
        // vars
        $terms = get_terms( array(
            'taxonomy' => 'fr_product_categories',
            'hide_empty' => false,
        ) );
            
        //print_r($options);
        //print_r($rule);
        
        if($rule['operator'] == "==")
        {
            $match = in_array( $rule['value'], $options['post_taxonomy']);
        }
        elseif($rule['operator'] == "!=")
        {
            $match = !in_array( $rule['value'], $options['post_taxonomy']);
        }
    
        return $match;
    
    }

    I hope this helps πŸ™‚

  • Hey James,

    That helped fixed many of the problems.
    The only issue I am having is with it updating on the AJAX calls.
    When I select a new category and then save and reload the page, the correct fields show up, but only on page reload.

    I used Chrome’s inspector to monitor the network calls. Every time a new category is selected (it is a drop-down) then there are two POST calls to admin-ajax.php. Both calls return a 200 status, but the page does not update to show the correct fields, until I save and reload.

    Are there other steps needed to make the AJAX calls update the edit page?

    This is the current state of the code now:

    function acf_location_rules_types_product_category($choices) {
        // create a new group for the rules called Terms
        // if it does not already exist
        if (!isset($choices['Products'])) {
            $choices['Products'] = array();
        }
        // create new rule type in the new group
        $choices['Products']['fr_product_categories'] = 'Category Name';
        return $choices;
    }
    
    function acf_location_rules_values_product_category($choices) {
        // get terms and build choices
        $all_categories = get_terms('fr_product_categories', array('hide_empty' => false, 'childless' => true, 'orderby' => 'name'));
        if(count($all_categories)){
            foreach($all_categories as $category){
                $choices[$category->term_id] = $category->name;
            }
        }
        return $choices;
    }
    
    function acf_location_rules_match_product_category($match, $rule, $options){
    	// validate
       if(!$options['post_id']){return false;}
    	$category = intval(get_post_meta($options['post_id'], 'product_category', true));
    	
    	if($rule['operator'] == "=="){
    		$match = $rule['value'] == $category;
    	}
    	elseif($rule['operator'] == "!="){
    		$match = $rule['value'] != $category;
    	}
    	return $match;
    }
  • Hi @brettzie

    I believe you were trying to get the category from a taxonomy custom field type. I’m afraid this is not possible because when you select the terms in the field input, the data is not saved yet. So, when you were trying to get the value using the get_post_meta() function, you will get the old value instead.

    Kindly use the taxonomy meta box instead to do it.

    If you want, you can also check the $options value by using the var_dump() function like this:

    function acf_location_rules_match_product_category($match, $rule, $options){
        var_dump($options);

    I hope this helps πŸ™‚

Viewing 4 posts - 1 through 4 (of 4 total)

You must be logged in to reply to this topic.