Overview

Modify individual facet values before they are saved into FacetWP’s index table.

Parameters

  • $params | array | An associative array of data to be indexed (see below)
  • $class | object | The indexer class

How to use custom PHP code?

PHP code can be added to your (child) theme's functions.php file. Alternatively, you can use the Custom Hooks add-on, or a code snippets plugin. More info

$params = [ 'post_id' => 123, 'facet_name' => 'my_facet', 'facet_source' => 'tax/category', 'facet_value' => '45', 'facet_display_value' => 'My Test Category', 'term_id' => 0, 'parent_id' => 0, 'depth' => 0, 'variation_id' => 0 ];

Except for $params['facet_source'], the $params array keys/values correspond to columns in the facetwp_index table:

How it works

The facetwp_index_row hook is one of the most powerful and most used hooks in FacetWP, because it can manipulate the values and labels for each facet at the moment they are stored in the index table.

To get how this works exactly, it is important to understand how FacetWP’s facetwp_index database table is structured. Below is an example of a small part of this indexing table:

An example of a part of FacetWP's indexing table.
An example of a part of FacetWP’s indexing table.

As you can see, the post with ID 4070 has four rows indexed for a facet named categories. These four rows correspond to four choices in the categories facet, each of which will make this post appear in the results when this choice is clicked.

Each of the rows in the facetwp_index table has a value in the following nine columns:

Column Explanation
id The table row ID.
post_id The post ID.
facet_name The facet name.
facet_value The raw, technical facet value, as shown in the URL when this facet choice is selected. This is the term slug if the facet’s data source is a taxonomy.
facet_display_value The label of the facet choice, as shown in the facet itself in the front-end. This is the term name if the facet’s data source is a taxonomy.
term_id The term ID. Only used if the facet’s data source is a taxonomy, 0 otherwise.
parent_id The term parent ID. Only used if the facet’s data source is a hierarchical taxonomy, 0 otherwise.
depth The term depth. Only used if the facet’s data source is a hierarchical taxonomy, 0 otherwise.
variation_id The product variation ID. Only used if the indexed post is a WooCommerce product and indexing of product variations is enabled, 0 otherwise.

It is important to keep in mind that the facetwp_index_row hook runs once on the insertion of each of these table rows. So it runs for each post ID, for each facet, and then for each value that this post has stored for that facet’s data source (generally a custom field or one or more terms in a taxonomy).

While it is running, you have access to all of the above values for the current row, via the $params variable. You can use these values to manipulate the facet_value and facet_display_value (or the other values) for the row, and pass them back to $params just before the data is inserted into the row.

Good to know is that if you set the $params['facet_value'] variable to an empty string, the insertion of the whole row will be skipped. This can be useful if you want to prevent certain facet values from being indexed. For example, if you want to index only specific levels in a term hierarchy.

Another important thing to remember is that when a facet has a taxonomy set as its data source, the term slug is stored in facet_value and the term name in facet_display_value.

Applications

The access to the indexing process and its variables makes this hook very versatile. Some things you can do with it:

You can find a lot more examples in our code snippet library.

Usage examples

Index only specific term levels

Hierachical taxonomy depth levels.
Hierachical taxonomy depth levels.

In facets that use a taxonomy as data source, the facetwp_index_row hook can be used to display only certain levels of the term hierarchy.

Because the hook has access to the depth level of each term as it is being indexed (with $params['depth']), you can define which depth levels of the hierarchy are included or excluded.

The first example below will index only the top-level terms (with depth == 0). To accomplish that, terms with depth levels > 0, which are all child levels, are excluded from being indexed, by setting $params['facet_value'] to an empty string. Using the example taxonomy on the right, only “North America” and its sibling terms will be shown in the facet:

How to use custom PHP code?

PHP code can be added to your (child) theme's functions.php file. Alternatively, you can use the Custom Hooks add-on, or a code snippets plugin. More info

add_filter( 'facetwp_index_row', function( $params, $class ) { if ( 'my_facet_name' == $params['facet_name'] ) { // Replace 'my_facet_name' with the name of your facet. if ( $params['depth'] > 0 ) { $params['facet_value'] = ''; // Don't index this row. } } return $params; }, 10, 2 );

To index only the top-level terms (depth == 0) and their direct children (depth == 1):

How to use custom PHP code?

PHP code can be added to your (child) theme's functions.php file. Alternatively, you can use the Custom Hooks add-on, or a code snippets plugin. More info

add_filter( 'facetwp_index_row', function( $params, $class ) { if ( 'my_facet_name' == $params['facet_name'] ) { // Replace 'my_facet_name' with the name of your facet if ( $params['depth'] > 1 ) { $params['facet_value'] = ''; // Don't index this row. } } return $params; }, 10, 2 );

The above examples exclude (lower) child levels from being indexed. It is also possible to exclude (higher) parent levels and keep child levels, by setting $params['depth'] > x to be indexed only. Or to keep only a child level, but not their parents or children, by setting $params['depth'] === x to be indexed only.

Three examples of this are shown below. Note that when higher levels are excluded, all lower levels that are indexed need to shift upward in the term hierarchy so that the highest included child level now becomes level 0. The example code in all snippets below accounts for that.

Use the following to index only direct child terms (depth == 1) and deeper levels. In other words, to skip the top-level terms (depth == 0):

How to use custom PHP code?

PHP code can be added to your (child) theme's functions.php file. Alternatively, you can use the Custom Hooks add-on, or a code snippets plugin. More info

add_filter( 'facetwp_index_row', function( $params, $class ) { if ( 'my_facet_name' == $params['facet_name'] ) { // Replace 'my_facet_name' with the name of your facet. if ( $params['depth'] > 0 ) { $params['depth'] = $params['depth'] - 1; // Shift the depth level one upwards for every child level. } else { $params['facet_value'] = ''; // Don't index the highest level. } } return $params; }, 10, 2 );

To index only terms on a specific depth, including all children at lower levels, you can use the following snippet. Make sure to set the desired level in line 3. Note that the top level is 0, so 2 in this example is the grandchild level, three levels deep:

How to use custom PHP code?

PHP code can be added to your (child) theme's functions.php file. Alternatively, you can use the Custom Hooks add-on, or a code snippets plugin. More info

add_filter( 'facetwp_index_row', function( $params, $class ) { if ( 'my_facet_name' == $params['facet_name'] ) { // Replace 'my_facet_name' with the name of your facet $depth = 2; // Set the desired depth to show, including its children. The top level is 0, so 2 is grandchild level. if ( $params['depth'] >= $depth ) { $params['depth'] = $params['depth'] - $depth; // Shift the depth level one upwards for every child level. } else { $params['facet_value'] = ''; // Don't index this row. } } return $params; }, 10, 2 );

To index only the first-level direct child terms (depth == 1), but not their parent or child terms:

How to use custom PHP code?

PHP code can be added to your (child) theme's functions.php file. Alternatively, you can use the Custom Hooks add-on, or a code snippets plugin. More info

add_filter( 'facetwp_index_row', function( $params, $class ) { if ( 'my_facet_name' == $params['facet_name'] ) { // Replace 'my_facet_name' with the name of your facet. if ( $params['depth'] === 1 ) { $params['depth'] = $params['depth'] - 1; // Shift the depth level one upwards for every child level. } else { $params['facet_value'] = ''; // Don't index the highest level. } } return $params; }, 10, 2 );

Index only children of one or more parents

To display only child terms of one specific parent term in a facet, you can use the “Parent term” setting (if the facet type has this setting).

To do this programmatically, or to display only child terms of multiple parents, add the following code to your (child) theme’s functions.php.

Add the parent ID(s) of which you want the child terms to be shown to the array in line 5. Make sure to re-index after adding or changing the code.

How to use custom PHP code?

PHP code can be added to your (child) theme's functions.php file. Alternatively, you can use the Custom Hooks add-on, or a code snippets plugin. More info

add_filter( 'facetwp_index_row', function( $params, $class ) { if ( 'my_facet_name' == $params['facet_name'] ) { // Replace 'my_facet_name' with the name of your facet. $parent_id = [ 305,306 ]; // List all parents of which the child terms should be shown. Can be one or more. $taxonomy = str_replace( 'tax/', '', $params['facet_source'] ); // Get the taxonomy used as the facet data source $ancestors = get_ancestors( $params['term_id'], $taxonomy ); // Get all ancestors of the term being indexed. $term_id_parents = array_intersect( $parent_id, $ancestors ); // Get the parent id(s) are among the ancestors. if ( $term_id_parents ) { // If the parent(s) is/are among the ancestors $term_id_parent = end( $term_id_parents ); // Store the highest level parent id (in case there are more) $parent_depth = count( get_ancestors( $term_id_parent, $taxonomy ) ); // Get parent depth $params['depth'] = $params['depth'] - ( $parent_depth + 1 ); // Shift the depth level based on the depth of the parent id } else { $params['facet_value'] = ''; // Don't index this row. } } return $params; }, 10, 2 );

A few things to keep in mind when using the above code:

  • For this code to work, the data source of the facet needs to be a taxonomy. The code will work with or without the facet’s Hierarchical setting enabled.
  • Make sure not to use the facet’s “Parent term” setting.
  • If you add multiple parent IDs that are at different hierarchical levels, each of their child trees is shifted upwards in the hierarchy until the highest child level is at level 0. The tree may then look different than the original one.
  • If you add parent IDs that are within the same vertical parent-child tree, the code takes the highest one in the hierarchy and shows the children of that parent.

To prevent one or more posts from being indexed for a certain facet, you can use the following code:

How to use custom PHP code?

PHP code can be added to your (child) theme's functions.php file. Alternatively, you can use the Custom Hooks add-on, or a code snippets plugin. More info

add_filter( 'facetwp_index_row', function( $params, $class ) { $post_ids = [ 123, 456, 789 ]; // add your post IDs here if ( 'my_facet_name' == $params['facet_name'] && in_array( $params['post_id'], $post_ids ) ) { // replace 'my_facet_name' with the name of your facet $params['facet_value'] = ''; // don't index this row } return $params; }, 10, 2 );

This will exclude the specified posts from the results if they would normally show up when filtering with the specified facet.

Note that this code will not prevent these post(s) from showing up in the unfiltered results. To prevent posts from being in the results at all, you can adapt your query, or use the facetwp_pre_filtered_post_ids hook.

Or, if you only want to prevent them from being in the filtered results, no matter which facet is used, you can use the facetwp_filtered_post_ids hook, or the following approach:

Exclude posts with a specific term from being indexed for all facets

To prevent posts that have a specific term from being indexed for all facets, you can use the following code:

How to use custom PHP code?

PHP code can be added to your (child) theme's functions.php file. Alternatively, you can use the Custom Hooks add-on, or a code snippets plugin. More info

add_filter( 'facetwp_index_row', function( $params, $class ) { $post_id = $params['post_id']; $excluded_terms = [ 'my_term', 'my_other_term' ]; // Add terms to be excluded $taxonomy = 'product_cat'; // The taxonomy that contains the terms foreach ( $excluded_terms as $term ) { if ( has_term( $term, $taxonomy, $post_id ) ) { $params['facet_value'] = ''; // Skip this row break; } } return $params; }, 10, 2 );

As in the previous example, this will exclude the specified posts from the results if they would normally show up when filtering with any facet.

And also here, this code will not prevent these post(s) from showing up in the unfiltered results. To prevent posts from being in the results at all, you can adapt your query, or use the facetwp_pre_filtered_post_ids hook.

As an alternative to the above code, you can also use the facetwp_filtered_post_ids hook.

Combine facet choices

Combine multiple facet choices into one choice:

How to use custom PHP code?

PHP code can be added to your (child) theme's functions.php file. Alternatively, you can use the Custom Hooks add-on, or a code snippets plugin. More info

add_filter( 'facetwp_index_row', function( $params, $class ) { if ( 'fruits' == $params['facet_name'] ) { // Replace 'fruits' with the name of your facet. $val = $params['facet_value']; if ( 'oranges' == $val || 'grapefruits' == $val || 'lemons' == $val ) { // Replace 'oranges'/'grapefruits'/'lemons' with the facet choices to combine (we use the technical name here). Note that || means OR. $params['facet_value'] = 'citrus-fruits'; // Replace 'citrus-fruits' with the new facet_value (technical name/slug). Don't use spaces or special characters. $params['facet_display_value'] = 'Citrus Fruits'; // Replace 'Citrus Fruits' with the new facet choice's display name. } } return $params; }, 10, 2 );

Important to distinguish here is that each facet choice consists of two values that are indexed and stored in the index table. The facet_value is its technical name (“slug”) as it appears in the URL after filtering. And the facet_display_value is the choice’s display value as it shows up in the facet itself in the front-end.

Another thing to notice is that in line 3 and 4 of the above example, we are using facet_value to select the choices that will be combined. You could also use facet_display_value here, as it is available in the hook’s parameters.

Split or add facet choices

This hook can also be used to add new rows to the indexing table, with the insert() function. The following code example splits comma-separated facet values into individual facet values. It then uses the insert() function to enter these values as new rows in the indexing table.

Say you have a facet with a choice apples, oranges, bananas. After implementing the below code, and doing a full re-index, you will now have three facet choices: apples, oranges, and bananas.

How to use custom PHP code?

PHP code can be added to your (child) theme's functions.php file. Alternatively, you can use the Custom Hooks add-on, or a code snippets plugin. More info

add_filter( 'facetwp_index_row', function( $params, $class ) { if ( 'my_facet_name' == $params['facet_name'] ) { // Replace 'my_facet_name' with the name of your facet // Split the original facetwp_display_value by comma $values = explode(",", $params['facet_display_value']); // Store each separate value as a new row foreach ($values as $value) { $value = trim( $value ); // Remove any whitespace from the beginning and end of the new value $params['facet_value'] = $value; $params['facet_display_value'] = $value; $class->insert( $params ); } $params['facet_value'] = ''; // skip the original row } return $params; }, 10, 2 );

Remove facet choices

With this hook you can also remove facet choices. The easiest way to do this is with the facet’s value modifiers (if it has that setting). But in some situations, this will not work. For example, if you have a facet that uses categories as data source, and there are multiple terms with the same name, but different slugs. To remove these duplicate terms, you need to be able to select them by facet_value (the term slug), and not facet_display_value (the term name, as used in the facet’s “Value modifiers” setting).

The following example assumes three facet choices, all with the label “X-lock” and with slugs x-lock, x-lock-2 and x-lock-3. The snippet removes the two facet choices with slugs x-lock-2 and x-lock-3:

How to use custom PHP code?

PHP code can be added to your (child) theme's functions.php file. Alternatively, you can use the Custom Hooks add-on, or a code snippets plugin. More info

add_filter( 'facetwp_index_row', function( $params, $class ) { $exclude_values = [ 'x-lock-2', 'x-lock-3' ]; // add the raw values / slugs of choices to remove if ( 'my_facet_name' == $params['facet_name'] && in_array( $params['facet_value'], $exclude_values ) ) { // replace 'my_facet_name' with the name of your facet $params['facet_value'] = ''; // don't index this row } return $params; }, 10, 2 );

Create a month/year facet

This hook can also be used to create a facet with months and years (or only years, or months) as facet choices.

First, create a facet (for example a Checkboxes facet), and set its Data Source to Post Date (or any custom field that stores a date in the YYYY-MM-DD format), like an ACF Date Picker field.

Then add the following code to your (child) theme’s functions.php. Make sure to change my_facet_name in line 2 to the name of your facet, and re-index.

A Checkboxes facet to filter by month and year.
A Checkboxes facet to filter by month and year.

Using this example code, the facet will display choices formatted as November 2024, determined by the F Y format passed in the date() function for the facet_display_value in line 5.

When selected, the facet choice will show as 11-2024 in the URL, as set in the facet_value (the “raw” technical value) in line 4. Note that we have set the facet_value to m-Y and not to Y-m. This way, you can have the months ordered correctly in the facet, by setting the facet’s “Sort by” setting to “Raw value”.

How to use custom PHP code?

PHP code can be added to your (child) theme's functions.php file. Alternatively, you can use the Custom Hooks add-on, or a code snippets plugin. More info

add_filter( 'facetwp_index_row', function( $params, $class ) { if ( 'my_facet_name' == $params['facet_name'] ) { // change "my_facet_name" to the name of your facet $raw_value = $params['facet_value']; $params['facet_value'] = date( 'm-Y', strtotime( $raw_value ) ); // Use "11-2024" for the facet choice in the URL, so you can set the facet's "Sort by" setting to "Raw value" and order the months correctly. $params['facet_display_value'] = date( 'F Y', strtotime( $raw_value ) ); // Use "November 2024" for the facet choice's display value } return $params; }, 10, 2 );
A Checkboxes facet to filter by year.
A Checkboxes facet to filter by year.

The date formats for the facet_value and facet_display_value can be customized. For example, to only show years, just use Y. This could for example be used to create a Slider facet showing years, using the Post Date as data source.

For abbreviated, 3-letter month names (e.g. Dec), use M instead of F.

For more formatting option, see this overview table of PHP’s DateTime format characters.

Create a past/future facet

A future-past Radio facet.
A future-past Radio facet.

This hook can also be used to create a facet to filter posts by past or future date. The date can be the post date or any custom field containing a date.

First, create a facet (for example a Radio facet), and set its Data Source to Post Date (or any custom field that stores a date in the YYYY-MM-DD format), like an ACF Date Picker field.

Then add the following code to your (child) theme’s functions.php. Make sure to change my_facet_name in line 3 to the name of your facet, and re-index.

This example creates an “Open” (future) and “Closed” (past) option.

To customize the text, for both choices change the values for facetwp_value (the technical value as shown in the URL) and facetwp_display_value (the choice as shown in the facet itself). Make sure that the facetwp_value values are lowercase and do not contain any spaces or special characters. Re-index again after making any changes.

How to use custom PHP code?

PHP code can be added to your (child) theme's functions.php file. Alternatively, you can use the Custom Hooks add-on, or a code snippets plugin. More info

add_filter( 'facetwp_index_row', function( $params, $class ) { if ( 'my_facet_name' == $params['facet_name'] ) { // Change "my_facet_name" to the name of your date-based facet $raw_value = $params['facet_value']; // The date field needs to be in YYYY-MM-DD format $date = new DateTime($raw_value); $now = new DateTime('now'); if ( $date > $now ) { // Date is in the future $params['facet_value'] = 'open'; // Lowercase, don't use spaces or special characters $params['facet_display_value'] = 'Open'; } else { // Date is in the past $params['facet_value'] = 'closed'; // Lowercase, don't use spaces or special characters $params['facet_display_value'] = 'Closed'; } } return $params; }, 10, 2 );

Index a serialized array

Some custom fields store their values as a serialized array, which looks like this:

How to use custom PHP code?

PHP code can be added to your (child) theme's functions.php file. Alternatively, you can use the Custom Hooks add-on, or a code snippets plugin. More info

a:2:{i:0;s:6:"Monday";i:1;s:8:"Thursday";}

FacetWP will recognize some custom field types that do this (like ACF Checkboxes fields) and will automatically unserialize the value while indexing. But this will not always be the case. There are also situations in which FacetWP does not recognize the field as being serialized, for example if a facet uses an ACF Relationship field or Post Object field as its data source, and the related field is a field that stores its data serialized, like an ACF Checkboxes field.

In these situations, you can use the facetwp_index_row hook as shown in the example below. To index each value within a serialized array, it first needs to be unserialized. Then each value in the array can be inserted individually into the database. And last but not least, the original (serialized) value needs to be skipped over:

How to use custom PHP code?

PHP code can be added to your (child) theme's functions.php file. Alternatively, you can use the Custom Hooks add-on, or a code snippets plugin. More info

add_filter( 'facetwp_index_row', function( $params, $class ) { if ( 'my_facet_name' == $params['facet_name'] ) { // Replace 'my_facet_name' with the name of your facet $values = maybe_unserialize( $params['facet_value'] ); if ( is_array( $values ) && ! empty( $values ) ) { foreach ( $values as $value ) { $params['facet_value'] = $value; // Set the choice's technical value (as seen in the URL). $params['facet_display_value'] = $value; // set the choice's display value (as seen in the facet). $class->insert( $params ); // insert each new value into the database as a new row. } $params['facet_value'] = ''; // skip the original row, by setting the technical value to nothing. } } return $params; }, 10, 2 );

More examples

See also

Last updated: January 9, 2025