Build product listing pages (CSR)

This is for:

Developer

Building product listing pages (PLPs) with Coveo Headless involves two main elements:

  1. Keeping the URL up to date as you navigate between pages using the Context controller

  2. Using the ProductListing controller to fetch product listings and display the results

A complete example of a listing page component is available in the sample project in the Headless repository.

Prerequisite

Make sure that you understand how to build product listing pages (PLPs).

Keep the URL up to date

Keep the URL state updated in Headless to ensure that the correct product listing page (PLP) is fetched when navigating between pages.

The context helps Headless determine which product listing page (PLP) to fetch products for.

For more information, Navigating between pages.

Initializing the ProductListing controller

After initializing your engine, you can pass in this instance to build the controller.

import { commerceEngine } from './Engine';
import { buildProductListing } from '@coveo/headless/commerce';

const productListing = buildProductListing(commerceEngine);

The ProductListing controller has a refresh method you can use to fetch product listings.

Display the listing pages using the ProductListing controller

In addition to ensuring that page navigation correctly updates the url using the Context controller, you must also display the products fetched by the ProductListing controller.

import {
  Cart,
  Search as HeadlessSearch,
  ProductListing,
} from '@coveo/headless/commerce';
import { useState, useEffect } from 'react';
import FacetGenerator from '../../facets/facet-generator/facet-generator';
import Pagination from '../../pagination/pagination';
import ProductList from '../../product-list/product-list';
import Sort from '../../sort/sort';

interface ISearchAndListingInterface {
  searchOrListingController: HeadlessSearch | ProductListing;
  cartController: Cart;
  navigate: (pathName: string) => void;
}

export default function SearchAndListingInterface(
  props: ISearchAndListingInterface
) {
  const {searchOrListingController, cartController, navigate} = props;

  const [searchOrListingState, setSearchOrListingState] = useState(
    searchOrListingController.state
  );

  useEffect(() => { 1
    searchOrListingController.subscribe(() =>
      setSearchOrListingState(searchOrListingController.state)
    );
  }, [searchOrListingController]);

  return (
    <div className="row">
      <div className="column">
        <FacetGenerator 2
          controller={searchOrListingController.facetGenerator()}
        />
      </div>
      <div className="column">
        <Sort controller={searchOrListingController.sort()} /> 3
        <ProductList 4
          products={searchOrListingState.products}
          controllerBuilder={searchOrListingController.interactiveProduct}
          cartController={cartController}
          navigate={navigate}
        ></ProductList>
        <Pagination controller={searchOrListingController.pagination()} /> 5
      </div>
    </div>
  );
}
Note

The previous component can be re-used for both displaying and interacting with results from both search and listing pages.

A complete example of how to build a PLP component is available in the Headless repository.

Within the sample project, you can find additional components that were omitted in this article, such as the BreadcrumbManager (displays a summary of the currently active facet values) and Summary (provides a summary of search results such as the number of results returned).