# Filters

# Introduction

Our filters feature allows you to fetch a product list based on selected options like color or size. These options are based on the product attributes added to the products on the page for each category.

# Retrieving filters

To build filtering in your application, first you need to retrieve filters from the BigCommerce API. To do that, you can use new useFetch composable.

The load method of useFetch composable will fetch filters from BigCommerce GraphQL API and return the raw response. The response from the GraphQL API is a little bit different than the response from BigCommerce REST API. For example, your response might look like this:

{
  "edges": [
    {
      "node": {
        "name": "Color",
        "__typename": "ProductAttributeSearchFilter",
        "attributes": {
          "edges": [
            {
              "node": {
                "value": "Black",
                "productCount": 1,
                "isSelected": false
              }
            },
            {
              "node": {
                "value": "Blue",
                "productCount": 1,
                "isSelected": false
              }
            },
            {
              "node": {
                "value": "Orange",
                "productCount": 1,
                "isSelected": false
              }
            },
            {
              "node": {
                "value": "Silver",
                "productCount": 1,
                "isSelected": false
              }
            }
          ]
        },
        "isCollapsedByDefault": false
      }
    },
    {
      "node": {
        "name": "Size",
        "__typename": "ProductAttributeSearchFilter",
        "attributes": {
          "edges": [
            {
              "node": {
                "value": "Large",
                "productCount": 1,
                "isSelected": false
              }
            },
            {
              "node": {
                "value": "Medium",
                "productCount": 1,
                "isSelected": false
              }
            },
            {
              "node": {
                "value": "Small",
                "productCount": 1,
                "isSelected": false
              }
            }
          ]
        },
        "isCollapsedByDefault": false
      }
    }
  ]
}

So to get the filter values, it's necessary to do some mapping to get each node. Based on this response, you can start building your UI for filters selection. Example implementation of fetching the filters might look like this:

setup() {
  const { load, loading: filtersLoading } = useFilters();
  const currentCategoryId = 1;
  const filters = ref([]);

  async function fetchAvailableFilters() {
    const rawFilters = await load({
      filters: {
        categoryEntityId: currentCategoryId
      }
    });

    return raw.edges.map((item) => item.node);
  }

  onMounted(() => {
    filters.value = fetchAvailableFilters()
  });

  return filters;
}

# Filtering products

Filtering products by attributes is only available via the of BigCommerce GraphQL API. Our useProduct example contains a method - filter which can be used to get filtered product response.

To make this call properly, it's necessary to properly format the filter parameters.

For example, let's say we want to filter products in our current category to only get products where the Color attribute equals Red.

const exampleFilters = {
  categoryEntityId: currentCategoryId,
  productAttributes: [
    {
      attribute: 'Color',
      values: ['Red']
    }
  ]
};

The attribute parameter should match as name parameter of the filter response from Retrieving filters section. The values parameter contains the array of attribute value parameters in the same response.

If you want to filter by more attributes, you can add more attribute/values to the productAttributes array.

const exampleFilters = {
  categoryEntityId: currentCategoryId,
  productAttributes: [
    {
      attribute: 'Color',
      values: ['Red', 'Blue']
    },
    {
      attribute: 'Size',
      values: ['Large']
    }
  ]
};

Example implementation of filtering products might look like this:

setup() {
  const { filter } = useProduct();
  const products = ref([]);
  const pageInfo = ref({});
  const sort = 'FEATURED';
  const itemsPerPage = 10;

  useFetch(async () => {
    const filters = {
      categoryEntityId: currentCategoryId,
      productAttributes: [
        {
          attribute: 'Color',
          values: ['Red', 'Blue']
        },
        {
          attribute: 'Size',
          values: ['Large']
        }
      ]
    }

    const res = await filter({
      filters,
      first: itemsPerPage,
      sort
    });

    products.value = res.data
    pageInfo.value = res.meta
  });
}

See UseProductInterface for more information about parameters and responses.

# Sorting

To use useProduct().filter method with sorting, it's necessary to make some changes with Sort by logic. BigCommerce GraphQL API requires other sorting values than REST API. Sorting values are added to themeConfig.js file, below you can find configuration proper for GraphQL API and sorting:

productsSortOptions: [
    { label: 'Featured', id: 1, value: { sort: 'FEATURED' } },
    { label: 'Relevance', id: 2, value: { sort: 'RELEVANCE' } },
    { label: 'Best selling', id: 3, value: { sort: 'BEST_SELLING' } },
    { label: 'Best reviewed', id: 4, value: { sort: 'BEST_REVIEWED' } },
    { label: 'Newest', id: 5, value: { sort: 'NEWEST' } },
    { label: 'Name: A to Z', id: 6, value: { sort: 'A_TO_Z' } },
    { label: 'Name: Z to A', id: 7, value: { sort: 'Z_TO_A' } },
    {
      label: 'Price from high to low',
      id: 8,
      value: { sort: 'HIGHEST_PRICE' }
    },
    { label: 'Price from low to high', id: 9, value: { sort: 'LOWEST_PRICE' } }
  ],

sort params like FEATURED or A_TO_Z should be added as sort param to useProduct().filter method:

const { filter } = useProduct();

const res = await filter({
  filters,
  first: 10,
  sort: 'FEATURED'
});

# Pagination

Default pagination does not exist in the BigCommerce integration so there is no way to create page functionality. However, there is a way to create Show more logic on your website.

The idea is to fetch first part of the product at start, and add every new fetched product to the list of products instead of replacing it. First fetch might load 10 products, next fetch would add new 10 products to the list of products - now 20 products would be visible on the page.

To understand how to build such a feature, first you should focus on the response of useProduct().filter method.

Example response might look like this:

{
  "data": [
    // List of products
  ],
  "meta": {
    "totalItems": 5,
    "pageInfo": {
      "hasNextPage": true,
      "hasPreviousPage": false,
      "startCursor": "WzEwMDAwMDAwMCwwLDkzXQ==",
      "endCursor": "WzEwMDAwMDAwMCwwLDg4XQ=="
    }
  }
}

Information to build "show more" functionality is included in meta.pageInfo param.

  • hasNextPage defines if there are more products to fetch
  • endCursor is the unique value for each product that can be used to define after which product we want to start fetching more products

Then, we can use the filter method and specify the after parameter, where endCursor should be used:

setup() {
  const { filter } = useProduct();
  const products = ref([]);
  const pageInfo = ref({});
  const sort = 'FEATURED';
  const itemsPerPage = 10;

  useFetch(async () => {
    const filters = {
      categoryEntityId: currentCategoryId,
      productAttributes: [
        {
          attribute: 'Color',
          values: ['Red', 'Blue']
        },
        {
          attribute: 'Size',
          values: ['Large']
        }
      ]
    }

    const res = await filter({
      filters,
      first: itemsPerPage,
      after: pageInfo.value.endCursor
      sort
    });

    products.value = res.data
    pageInfo.value = res.meta
  });
}

Now, itemsPerPage number of products will start fetching products after last where the previous fetch left off.

To create a feature that adds new product to previous list of products, useFetch is a very helpful method to use. It returns { fetch } function, that can use used to trigger its effect again.

WARNING

There is a bug in @nuxtjs/composition-api package when useFetch is used with computed properties. It throws the error: [Vue warn]: Write operation failed: computed value is readonly.. It does not break the functionality, but this error could be observed in the console. To avoid this error, there is a [workaround](https://github.com/nuxt-community/composition-api/issues/19.

Example implementation of filtering products with show more functionality:

setup() {
  const route = useRoute();
  const { filter } = useProduct();

  const filterProductsResponse = ssrRef({}, route.value.fullPath);
  const products = ref([]);
  const after = ref('');

  const { fetch: refetchProducts } = useFetch(async () => {
    const filters = prepareFilters();

    const res = await filter({
      filters,
      after: after.value,
      first: itemsPerPage,
      sort
    });

    products.value = products.value.length
      ? [...products.value, ...res.data]
      : res.data;
    filterProductsResponse.value = res;
  });

  const { pagination, pageInfo } = usePagination(filterProductsResponse);

  const showMore = () => {
    if (pageInfo.value?.hasNextPage) {
      after.value = pageInfo.value.endCursor;
      refetchProducts();
    }
  };

  return {
    products,
    showMore
  }
}

# Limitations

Maximum 50 products can be fetched during 1 fetch - limitation of BigCommerce GraphQL API.