Indexing
During a process called indexing, FacetWP analyzes your site and stores facet data into a custom database table for quick lookups.
How to run the indexer
Whenever facets are added or edited, save your changes and then press the Re-index button. This completely rebuilds the index table.
If you press the Stop indexer button while the indexer is running, the index will remain incomplete until the next time you re-index.
While the indexer is running, you can click the rotating icon to see its progress.
It’s recommended to keep the FacetWP settings screen open while the indexer is running.
In some situations, it may be needed to trigger indexing programmatically or with a cron schedule.
When to run the indexer
In general, FacetWP will let you know when you need to re-index, by displaying a message in the top right corner of the admin screen after you save facet settings.
Re-indexing is only needed:
- when facets are added.
- when facet settings have changed.
- when content is imported programmatically, for example with WP All Import.
- when a category or term’s hierarchy has changed (e.g. changing to a new parent term).
- when a category or term’s custom field content has changed. (Terms can have custom fields added by Advanced Custom Fields or Pods).
- after adding hooks that influence the indexing process.
- after making changes to the registered post types.
- after purging the index table.
- when solving indexing issues.
Other indexing actions
Show indexer stats
Shows the last time a full re-index has run.
Show indexable post types
Lists all post types that will be indexed. If a desired post type is not in the list, read this section on how to fix this.
Purge the index table
Deletes and re-creates the facetwp_index database table. This can be helpful in resolving database migration issues or sometimes with other issues like a “The index table is empty” error.
Make sure to re-index again after purging the index table.
Common indexing issues
Fix a stalled indexer
FacetWP’s indexer can stall temporarily, for several reasons. If this happens, the first thing to do is wait a few minutes. FacetWP includes built-in resume functionality. It should resume automatically after a minute or two, if you keep the FacetWP settings screen open.
In specific circumstances, the indexer can get permanently stuck, often around the same percentage. These are the most common causes:
Fix memory exhaustion
The server running out of memory is the most common cause of a stuck indexer. This can be confirmed in the server’s error log. If you don’t have access to your server’s error log, you can confirm it as follows:
- First enable WP_DEBUG and WP_DEBUG_LOG in your wp-config.php file.
- Then, start a re-index by clicking the Re-index button, and wait until the indexer is definitively stuck.
- After that, go to your site’s
wp-content/
directory on your server and find the text file calleddebug.log
. Open it in a text editor to view your server’s error log. - The log file can be very large. Check for errors near the bottom, around the time the indexer last got stuck, which is probably the last error logged. Most likely you’ll find a so-called “Fatal error” relating to memory, something like: “PHP Fatal error: Allowed memory size of {x} bytes exhausted (tried to allocate {x} bytes)”.
If you find there are memory exhaustion errors, the next step is to give WordPress more memory, while making sure this amount does not exceed the server’s memory limit.
Fix a .htpasswd login blocking resuming
To bypass PHP timeout issues, FacetWP’s indexer makes a series of HTTP requests to itself. If your site uses HTTP Basic Authentication (.htpasswd), you’ll need to tell FacetWP how to log in.
Add the following into functions.php
or into the Custom Hooks add-on, and add your username/password to 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( 'http_request_args', function( $args, $url ) { if ( 0 === strpos( $url, get_site_url() ) ) { $args['headers'] = [ 'Authorization' => 'Basic ' . base64_encode( 'YOUR_USERNAME:YOUR_PASSWORD' ) // Change to your username and password ]; } return $args; }, 10, 2 );
Fix WP Engine settings
If you are hosting your website on WP Engine and you are experiencing problems with FacetWP’s indexer stalling or not indexing all your posts, see the fix below.
Fix a “The index table is empty” error
If you see a “The index table is empty” message during indexing, click the Re-index button again to restart the indexer. If that does not solve the issue, purge the index table and then re-index.
If that also does not clear up the error, check if any of the following situations apply:
- The post types you are trying to index are not searchable. FacetWP only indexes searchable post types.
- You have Polylang or WPML installed without FacetWP’s Multilingual add-on. If that is the case, install the add-on and re-index.
- You only have one or more of these four facet types: Search facets, Pager facets, Sort facets and Reset facets. These facet types do not require any indexing to work. After indexing, the whole “Rows” column will be empty, and you will get a “The index table is empty” message, which is correct and expected behavior, as the index table is indeed empty.
Fix issues with indexing post types
If a certain post type is not getting indexed, or if you get a “The index table is empty” error when trying to re-index, the reason can be that this post type is not being indexed by FacetWP.
You can check which post types FacetWP indexes with the “Show indexable post types” action of the “Re-index” button in FacetWP’s settings.
The reason for a post type not being included in this list, is that FacetWP by default only indexes “searchable” post types.
For a post type to be “searchable”, the exclude_from_search
argument of the register_post_type() function must be set to false
. Post types can be registered with this function in your theme code, in functions.php, or with a custom post type plugin (like Advanced Custom Fields). In that last case, exclude_from_search
will be a setting (in ACF it is located under: Post Types > Edit Post Type > Advanced Settings > Visibility > Exclude from Search).
As its name implies, the exclude_from_search
argument also determines whether to exclude posts with this post type from the front-end WordPress search results. Keep this in mind when choosing how to fix this. There are basically three options:
Ways to fix indexing specific post types
The best way to fix indexing for your (custom) post type depends on how it is registered. With the first three options below, be aware that if you apply this, the posts of this post type will show up in the WordPress front-end search results. If you don’t want this, go with option 4.
- If you are using a plugin to register your custom post type, there will be a setting to disable
exclude_from_search
. In Advanced Custom Fields it is located under: Post Types > Edit Post Type > Advanced Settings > Visibility > Exclude from Search:
- If you have access to the code where your post type is registered, set the
exclude_from_search
argument of theregister_post_type()
function tofalse
. If there is noexclude_from_search
argument, you can add it:
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
$args = array( //...other arguments 'public' => true, 'exclude_from_search' => false, // add this, or if it already exists, set it to false //...other arguments );
- If you don’t have access to the
register_post_type()
function, you can use a hook to set theexclude_from_search
argument tofalse
:
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( 'register_post_type_args', function( $args, $post_type ) { if ( 'my_post_type' === $post_type ) { // change 'my_post_type' to your post type $args['exclude_from_search'] = false; } return $args; }, 10, 2 );
- If you want to index and filter post types that you don’t want in your search results, it is also possible to force FacetWP to index non-searchable post types, with the facetwp_indexer_query_args hook. This hook can also be used to force FacetWP to index posts that have a
post_status
set to something else thanpublic
, like for example attachments.
Fix empty row counts
After indexing is complete, in the “Settings > FacetWP > Facets” overview screen’s “Rows” column, you’ll see the number of rows in the facetwp_index
database table that have been indexed for that facet.
If a particular facet has no rows indexed, something has gone wrong while indexing the posts for that facet. Most of the time the solution can be found by checking the facet’s Data Source setting. Make sure that you select a valid data source and check if your posts have (valid) values saved for the selected field. After making corrections, re-index again to see the updated row counts. To check if a facet is working okay in general, you can test with its Data Source set to “Post Type” and re-index.
Note that there are four facet types that will always have an empty “Rows” column: Search facets, Pager facets, Sort facets and Reset facets. These facet types do not require any indexing to work. They will also have an empty “Source” column:
This also means that if you have only one or more of these four facet types, the whole “Rows” column will be empty, and you will get a “The index table is empty” message, which is correct and expected behavior, as the index table is indeed empty.
Fix indexing issues with WP Engine
If you are hosting your website on WP Engine and you are experience problems with FacetWP’s indexer stalling or not indexing all your posts, try adding the following line to wp-config.php (not functions.php):
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
define( 'WPE_GOVERNOR', false );
WP Engine limits long queries (longer than 1024 characters) for performance reasons. The above line in wp-config.php prevents that.
Fix indexing issues with very high post IDs
In the rare case that you have post IDs that are higher than 4294967295
(2^32-1
), these posts will not get indexed properly because post IDs higher than this number cannot be stored in FacetWP’s indexing database table. This will lead to empty facets or facets with choices missing, depending on if all or some post IDs are above this limit.
Fortunately, there is an easy fix. Add the following code to your (child) theme’s functions.php:
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_use_bigint', '__return_true' );
Improve indexing speed
If your website has a lot of content, indexing can take a long time. If you want to speed up the indexing process, see this section on our performance page about what influences the speed and some things you can do.
One simple way of speeding things up is to use the facetwp_indexer_query_args hook to limit indexing to the post types you are actually using with FacetWP. To check which post types FacetWP currently indexes, click the “Show indexable post types” button in the settings, as shown in the image on the right.
How to index serialized data
With FacetWP, it’s possible to index custom fields stored as a serialized array.
Let’s say you have a facet named days_of_week
that uses a custom field with the same name. In the database, an example postmeta row 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";}
To index it, add the following code to functions.php
, then hit the Re-index button.
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
function index_serialized_data( $params, $class ) { if ( 'days_of_week' == $params['facet_name'] ) { $values = (array) $params['facet_value']; foreach ( $values as $val ) { $params['facet_value'] = $val; $params['facet_display_value'] = $val; $class->insert( $params ); } return false; // skip default indexing } return $params; } add_filter( 'facetwp_index_row', 'index_serialized_data', 10, 2 );
How to trigger the indexer programmatically
If you want to write your own functions to trigger re-indexing, use the following code to programmatically run the indexer:
Re-index all posts
To programmatically do a full re-index, use:
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
FWP()->indexer->index();
Re-index a single post
To programmatically re-index a single post, set the $post_id
parameter:
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
$post_id = 12345; // Must be an integer! FWP()->indexer->index( $post_id );
Re-index specific posts
To programmatically re-index multiple post IDs, use:
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
$post_ids = [ 8942, 8943, 8944 ]; // Post IDs to re-index. Use integers. foreach ( $post_ids as $post_id ) { FWP()->indexer->index( $post_id ); }
Re-index specific facets for specific posts
To programmatically re-index only specific facets for specific post IDs, use:
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
$post_ids = [ 8942, 8943, 8944 ]; // Post IDs to re-index. Use integers. $facet_names = [ 'price', 'stock_status', 'brand' ]; // Facets to re-index. $facets = []; foreach ( $facet_names as $name ) { $facet = FWP()->helper->get_facet_by_name( $name ); if ( false !== $facet ) { $facets[] = $facet; } } foreach ( $post_ids as $post_id ) { FWP()->indexer->index_post( $post_id, $facets ); }
Re-index specific facets for all posts
To programmatically re-index only specific facets for all post IDs, use:
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
$post_ids = FWP()->indexer->get_post_ids_to_index(); // Get all indexable post IDs. $facet_names = [ 'price', 'stock_status', 'brand' ]; // Facets to re-index. $facets = []; foreach ( $facet_names as $name ) { $facet = FWP()->helper->get_facet_by_name( $name ); if ( false !== $facet ) { $facets[] = $facet; } } foreach ( $post_ids as $post_id ) { FWP()->indexer->index_post( $post_id, $facets ); }
Trigger one-time re-indexing with WP-Cron
The above indexing function can be used in a WP-Cron event that runs only once, scheduled with the wp_schedule_single_event() function.
This can be useful if you want to trigger a one-time indexing event at a specific moment, for example after finishing an import. The event can be scheduled to run immediately, using time()
in the first parameter. Or you can specify a timestamp to let it run at a specific time later.
The following example shows how to schedule an immediate, one-time event that performs a full re-index of all posts.
The code needs to be placed in your (child) theme’s functions.php, except the wp_schedule_single_event()
function, which needs to be placed in your custom code, in a hook or function where you want to initiate re-indexing, for example after finishing an import:
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
function fwp_single_index( ) { FWP()->indexer->index(); // Re-index all posts } add_action( 'fwp_single_index', 'fwp_single_index' ); // Place this in a hook or function where you want to initiate indexing, for example after finishing an import. wp_schedule_single_event( time(), 'fwp_single_index' );
To do the same for a single post, you can pass its post ID in wp_schedule_single_event()
. Note that it needs to be passed as an array, even though it is a single post ID. Also make sure the post ID is an integer, not a numerical string:
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
function fwp_single_index( $post_id ) { FWP()->indexer->index( $post_id ); // Re-index this post } add_action( 'fwp_single_index', 'fwp_single_index' ); // Place this in a hook or function where you want to initiate indexing, for example after finishing an import. wp_schedule_single_event( time(), 'fwp_single_index', array( 456 ); // Re-indexes postID 465. Don't add more than one post ID to the array, that will NOT work. See the next example.
If you want to re-index multiple posts at once, keep in mind that passing them in an array does not work, because wp_schedule_single_event()
passes all post IDs in the array to the callback function as separate arguments. The solution is to pass them as a nested array:
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
function fwp_single_index( $post_id ) { foreach ( $post_id as $id ) { FWP()->indexer->index( $id ); // Re-index this post } } add_action( 'fwp_single_index', 'fwp_single_index'); // Place this in a hook or function where you want to initiate indexing, for example after finishing an import. wp_schedule_single_event( time(), 'fwp_single_index', array ( array ( 123,456,789 ) ) ); // Use a nested array for multiple posts. For a single post ID see the previous example.
Specify a time to run the one-time re-indexing event
All three examples above schedule the indexing event to run “now”, by setting the first parameter (the UNIX timestamp) of wp_schedule_single_event()
to time()
. If you need the event to run at a specific time later, you can use a relative format like time() + 3600
(one hour from now).
Or you can use PHP’s strtotime function with a relative date-time format. The following example schedules the event to index all posts at 01:00 hrs in the upcoming night:
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
function fwp_single_index( ) { FWP()->indexer->index(); // Re-index all posts } add_action( 'fwp_single_index', 'fwp_single_index' ); // Place this in a hook or function where you want to initiate indexing, for example after finishing an import. $timestamp = strtotime('tomorrow 01:00:00'); // Calculate the UNIX timestamp for the upcoming night 01:00 hr. wp_schedule_single_event( $timestamp, 'fwp_single_index' );
Testing the one-time re-indexing event
While testing the one-time event, be aware that WP-Cron is only triggered when there is some activity on the site on the front-end. If you don’t see the post(s) being re-indexed, make sure to load a few front-end pages of your site. Also keep in mind that after the front-end is triggered, it takes a minute for the schedule to actually run, and then for the indexer to start running and finishing (which can take a while depending on the number of posts and facets). You can follow the indexing progress by reloading the FacetWP admin page and clicking the rotating icon (or click “Show indexer stats” to see when it has last finished indexing).
While testing, you may want to disable FacetWP’s automatic indexing temporarily. Or, if your hook or function triggers the one-time event regularly, disable it permanently.
Note that if you are using wp_schedule_single_event()
in code that runs on WP’s init
hook, you need to make sure to use it with a priority of 21
or later (see the explanation above).
Trigger periodic re-indexing with WP-Cron
If you need to schedule a periodic re-index with WP-Cron, you can use the Schedule Indexer add-on. This plugin adds a WP-cron event that runs a full re-index on an hourly
WP-Cron schedule. You can also choose one of the other built-in schedules (twicedaily
, daily
and weekly
), or create your own custom schedule.
While testing the indexing schedule you have set with the Schedule Indexer add-on, be aware that WP-Cron is only triggered when there is some activity on the site on the front-end. If you don’t see the post(s) being re-indexed, make sure to load a few front-end pages of your site. If you don’t want the cron schedule to be dependent on this shortcoming of WP-Cron, you can also trigger re-indexing with a (“real”) server cron:
Trigger re-indexing with WP-CLI and server cron
If you prefer the command line, you can also use WP-CLI to manually trigger re-indexing.
Or, if you want to use a cron schedule to control indexing, you can use WP-CLI indexing commands in a server cron job. This can be useful too if you disabled WP-Cron for performance reasons, preventing you from using the Schedule Indexer add-on. Real server cron is also the best approach if you want your cron schedule to always run exactly at the scheduled time, independent of front-end site activity (which is the disadvantage of using WP-Cron).
With FacetWP’s built-in WP-CLI indexing command options you can also do partial re-indexes of only specific post types, post ID’s and facets, and you can purge the index table, as a whole or partially.
Re-indexing with WP-CLI (optimally triggered by a server cron job) is the recommended approach for indexing high-content sites, or sites with large amounts of content imported regularly. In these cases the automatic indexing process can become problematic. Using WP-CLI will give you full control over what is being indexed, when the indexing process runs exactly, and at which frequency. In this approach, FacetWP’s automatic indexing should be turned off with the facetwp_indexer_is_enabled hook.
Trigger re-indexing with WP All Import
FacetWP doesn’t automatically index content added via the WP All Import plugin.
Fortunately, there are there are hooks that can be used that allow FacetWP to automatically detect and index imported content.
Disable automatic indexing
It is possible to disable automatic (re-)indexing process, with the facetwp_indexer_is_enabled hook:
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_indexer_is_enabled', '__return_false' );
This can be useful if you are using WP-CLI to trigger re-indexing, or if you are using WP-Cron to trigger non-recurring or recurring re-indexing. Or if you simply want to (temporarily) pause automatic indexing when importing content or testing your custom re-indexing code.
It is also possible to disable automatic indexing for certain types of content.