Search code examples
phpwordpresswoocommerceadvanced-custom-fields

ACF - filter relationship query to display WooCommerce product available in this category


I'm trying to create a custom category product sort order in WooCommerce using Advanced Custom Fields. I have found a great guide to set it up. The approach is:

  1. Add the ACF relationship field to the category page.
  2. Config it to display only products.
  3. Add a function that orders the category page based on the products you've added.

It works great! The problem I have is that it always displays all the available products and not only the product available in this category.

I'm trying to use this function but the tag_id is not working.

add_filter('acf/fields/relationship/query', 'my_acf_fields_relationship_query', 10, 3);
function my_acf_fields_relationship_query( $args, $field, $post_id ) {

$args['tag_id'] = $category_id;

return $args;
}

Any suggestions?


Solution

  • You want to filter by product category terms, so you should not use:

    [tag_id]
    

    But instead use:

    [term_id]
    

    You follwed the tutorial, but the filter function is not working. You have created the custom field and inserted the function to create your custom product order. What is not working, if I got your question the right way, is the function that fetches an array of all the product IDs within a specific category. So you are getting all the available products and not the ones of the category you selected.

    This should have been part of your question so others can find a solution:

    This is the code from the tutorial you used: https://www.igoo.co.uk/2016/10/setting-a-custom-category-specific-product-sort-order-in-woocommerce-using-advanced-custom-fields/

    function my_custom_product_order($q) {
      if(!is_admin())
      {
        // fetch current category id from active query
        $category_id = $q->get_queried_object_id();
    
        // get array of all product IDs in current category
        $product_ids = get_category_product_ids($category_id);
    
        // get preferred order from ACF field
        $product_ids_order_preferred = get_field('product_order', 'product_cat_' . $category_id);
    
        // if we have some product sort order set…
        if($product_ids_order_preferred)
        {
            // merge our preferred category ids array with the array of all products ids, and remove duplicates
            $product_ids = array_unique(array_merge($product_ids_order_preferred, $product_ids));
        }
    
        // set the 'posts__in' argument to the new array of post IDs (unfortunately wordpress doesn’t let you just pass an array of IDs straight in here)
        $q->set('post__in', $product_ids);
    
        // set the query orderby value to observe the posts__in field
        $q->set('orderby', 'post__in');
      }
    
      remove_action('woocommerce_product_query', 'custom_pre_get_posts_query');
    }
    add_action('woocommerce_product_query', ‘my_custom_product_order’);
    

    In Line 7 of the code above, you are using the "get_category_product_ids($category_id)" function and give the $category_id as a parameter.

    The "get_category_product_ids" function in your tutorial looks like this:

    // helper function to fetch all product IDs from a specific category ID
    
    function get_category_product_ids($category_id) {
        $args = array(
            'post_type' => 'product',
            'post_status' => 'publish',
            'fields' => 'ids',
            'posts_per_page' => -1,
            'tax_query' => array(
                array(
                    'taxonomy' => 'product_cat',
                    'field' => 'term_id',
                    'terms' => $category_id,
                    'operator' => 'IN'
                )
            )
        );
    
        $ids = get_posts($args);
    
        return $ids;
    }
    

    This function gets the parameter $category_id and uses it to make a post query and saving the resulting ids of the tax query.


    This is the actual answer, which might help you:

    If you want to find out why it is not working, you should first have a look at the $category_ id variable, because this value is the most important to make it work. So you can have a look if there is data inside the variable with var_dump inside your function after setting the variable:

    var_dump($category_id)
    

    Is the variable set correctly and do have data when the "my_custom_product_order" function is called? You should get the id of the current viewed category.

    If you not get an id inside my_custom_product_order

    you should have a look at the "get_queried_object_id()" function. It is possible to get this value with another way. The "get_queried_object()" function returns a WP_Term object. So you can also do:

    $category_id = $q->get_queried_object();
    $category_id = $category_id->term_id;
    

    Maybe you now have the id you need.

    If not, you should check the parameter $q, what is it for? Maybe this could cause the problem. You can try something like:

    if (is_product_category()) {
        $q = get_queried_object();
        $term_id = $q->term_id;
    }
    

    If you are getting an id inside my_custom_product_order

    then you should have a look at the "get_category_product_ids" function. Does the parameter work? Try var_dump inside this function and see if there is value handed over to the function. If not, you could get the variable another way. This seems redundantly and makes the parameters useless, but this way you can make sure that there is a category ID for your tax query. Put this at the start of your "my_category_product_ids":

    $category_id = get_queried_object();
    $category_id = $category_id->term_id;
    

    Hope this will help you finding out why it's not working. Without knowing that it will be hard to fix the problem. If I'm right, the problem is with your $category_id not having a value for making the functions work.