Support

Account

Home Forums General Issues Filter products/categories/ by ACF field

Solved

Filter products/categories/ by ACF field

  • Hello,
    I try to filter the list of categories of the products received bu the rest api.
    I add ‘myfield’ as ACF field.
    With the plugin ACF-to-rest-api I can see the field in the rest api result under acf : {}

    This url returns all the categories.
    https://mywebsite/wp-json/wc/v3/products/categories/

    I want to be able to filter a custom field added by ACF
    https://mywebsite/wp-json/wc/v3/products/categories/?myfield=testvalue

    Could someone help me ?

    I suppose there is a filter or an action to add in the functions.php file but everything I tried returned all the categories without any filter.

    What’s also strange, for the products, I can see in the rest api result the metadata with the values added by ACF
    For the category, the metadata aren’t visible.
    In the database the values are stored in termmeta for the categories and in postmeta for the products.
    If I’m right, the product is a post and the category is a taxonomy.

    Thanks in advance,

  • Ok I think I understand what you are trying to do, but correct my if I’m wrong.

    You want to retrieve TERMS from the taxonomy CATEGORY, but only those terms that have a specific value filled out in a custom field.

    There is an article in the ACF documentation describing how to do this if you were querying posts instead of taxonomy-terms: https://www.advancedcustomfields.com/resources/creating-wp-archive-custom-field-filter/

    However, I believe the same principle can be applied to pre_get_terms (instead of pre_get_posts).
    The filter pre_get_terms is called inside WP_Term_Query so it should work for api requests: https://developer.wordpress.org/reference/classes/wp_term_query/get_terms/

  • I’m not sure I explained well what I try to reach…

    To be sure :
    Products = post
    Categories = taxonomy

    When I go to this endpoint : https://mywebsite/wp-json/wc/v3/products/categories/
    I receive all the categories available for the products from the api.
    So there isn’t any filter. Screenshot enclose

    Before I will create a new category I need to know if the category already exist or not.

    I add a ACF field on the category to insert a unique ID.
    On the screenshot you can see coming from the plugin ACF-to-rest-api
    “acf”: {
    “id_category_mercator”: “merca1”
    },

    So the unique ID is “merca1”

    Now I want to ask the api to return me all the categories where there is “merca1” in the field “id_category_mercator”.
    Those values are stored in the table termmeta

    If it’s working, the api will return me 1 category and not all the list.

    Is it so more clear what I’m looking for or are your samples the correct ones ?

    Thanks in advance,

  • I believe my earlier example could work, I have modified the code from the acf-article and I believe this should work:

    $GLOBALS['my_query_filters'] = array( 
    	'field_1' => 'id_category_mercator',
    );
    
    add_action('pre_get_terms', 'my_pre_get_terms', 10, 1);
    function my_pre_get_terms( $query ) {
        
    	// bail early if is in admin
    	if( is_admin() ) return;
    	
    	
    	// bail early if not main query
    	// - allows custom code / plugins to continue working
    	if( !$query->is_main_query() ) return;
    	
    	
    	// get meta query
    	$meta_query = $query->get('meta_query');
    
    	
    	// loop over filters
    	foreach( $GLOBALS['my_query_filters'] as $key => $name ) {
    		
    		// continue if not found in url
    		if( empty($_GET[ $name ]) ) {
    			continue;
    		}
    		
    		
    		// get the value for this filter
    		// eg: https://mywebsite/wp-json/wc/v3/products/category?id_category_mercator=merca1
    		$value = explode(',', $_GET[ $name ]);
    		
    		
    		// append meta query
        	$meta_query[] = array(
                'key'		=> $name,
                'value'		=> $value,
                'compare'	=> 'IN',
            );
            
    	} 
    	
    	
    	// update meta query
    	$query->set('meta_query', $meta_query);
    
    }

    All I did was change the $GLOBALS variable at the top to use your acf fieldname, and then I changed the names of the filter and the function.

    I don’t know if this will work because I’m not sure if ACF data on categories is really stored in the term_meta table. But you could add this to your functions.php and try to query the category endpoint with ?id_category_mercator=merca1 we could find out.

  • Unfortunately I receive now an error on my request :
    Fatal error: Uncaught Error: Call to undefined method WP_Term_Query::is_main_query()

    If I comment your line
    if( !$query->is_main_query() ) return;

    I receive another error : Fatal error: Uncaught Error: Call to undefined method WP_Term_Query::get()
    For the line
    $meta_query = $query->get('meta_query');

    I can confirm you that the ACF data’s are for the categories are stored in the “termmeta” table. Please check screenshot.

  • I have experimented a bit and I can confirm the following works for regular categories:

    $GLOBALS['my_query_filters'] = array(
    	'field_1' => 'id_category_mercator',
    );
    
    add_action('pre_get_terms', 'my_pre_get_terms', 10, 1);
    function my_pre_get_terms( $query ) {
        
    	// bail early if is in admin
    	if( is_admin() ) return;
    	
    	// bail early if not main query
    	// - allows custom code / plugins to continue working
    	//if( !$query->is_main_query() ) return;
    
    	// get meta query
    	$meta_query = $query->meta_query;
    	
    	// loop over filters
    	foreach( $GLOBALS['my_query_filters'] as $key => $name ) {
    		
    		// continue if not found in url
    		if( empty($_GET[ $name ]) ) {
    			continue;
    		}
    		
    		// get the value for this filter
    		// eg: https://mywebsite/wp-json/wc/v3/products/category?id_category_mercator=merca1
    		$value = explode(',', $_GET[ $name ]);
    		
    		
    		// append meta query
        	$meta_query->queries[] = array(
                'key'		=> $name,
                'value'		=> $value,
                'compare'	=> 'IN',
            );
            
    	} 
    	
    	// update meta query
    	$query->meta_query = $meta_query;
    }

    You might want to figure something out to replace the commented out line of code:
    //if( !$query->is_main_query() ) return;

    But I don’t know what other functionality your project has that could cause/suffer conflicts.

  • Hello,
    Thanks a lot. That’s seems also to work for me.
    For the code
    if( !$query->is_main_query() )
    isn’t it a possibility to check if the field is inside the url ?
    if( isset($_GET['id_article_mercator'])

    After that I can’t post a value … Is it better to create a new post for that or do you have a quick solution ?

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

You must be logged in to reply to this topic.