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

FacetWP indexer buttonsWhenever 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.

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:

Other indexing actions

Show indexable post types

FacetWP indexing: show indexable post typesLists all post types that will be indexed. If a desired post type is not in the list, make sure that the exclude_from_search parameter of the register_post_type() function is set to false (and re-index afterwards).

Alternatively, you could use the facetwp_indexer_query_args filter to force a non-searchable post type to be indexed.

Purge the index table

FacetWP Indexing: purge the index tableDeletes 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

Solving a stalled indexer

The indexer can stall occasionally: the server/WordPress ran out of memory, there was a power outage, etc. Fortunately, FacetWP includes built-in resume functionality. It should resume automatically after a minute or two, assuming you keep the FacetWP settings screen open.

If you do notice a stalled indexer, check your web server’s PHP error log for any clues.

If your site is behind a .htpasswd login, the indexer might be blocked from resuming. See the solution below.

If your site is hosted on WP Engine, see the fix below.

Solving a “The index table is empty” error

If you see a “The index table is empty” error 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 the post types you are trying to index are searchable. FacetWP only indexes searchable post types.

A “The index table is empty” error can also happen if you have Polylang or WPML installed without FacetWP’s Multilingual add-on. If that is the case, install the add-on and re-index.

Solving issues with indexing post types

If certain post types are not getting indexed, or if you get a “The index table is empty” error when trying to re-index, make sure that the exclude_from_search parameter of the register_post_type() function is set to false (and re-index afterwards).

The exclude_from_search query parameter determines whether to exclude posts with this post type from the front-end WordPress search results. FacetWP by default only indexes searchable post types.

FacetWP indexing: show indexable post typesYou can check which post types FacetWP indexes with the “Show indexable post types” action of the “Re-index” button in FacetWP’s settings.

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. See the hook’s usage example.

Solving indexing issues for password-protected sites

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:

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' )
        ];
    }
    return $args;
}, 10, 2 );

Solving 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:

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.

How to trigger the indexer programmatically

If you want to write your own functions to trigger re-indexing, use the following code to programmatically do a full re-index:

FWP()->indexer->index();

If you want to re-index a single post instead, set the $post_id parameter:

$post_id = 12345; // must be an integer
FWP()->indexer->index( $post_id );

Trigger periodic re-indexing with WP-Cron

If you need to schedule a periodic re-index with WP-Cron, you can use the sample plugin below.

Save the code to a PHP file, e.g. facetwp-schedule-indexer.php and upload the file to your Plugins folder. You can place it in a separate folder (like most other plugins) if you like. Then in WP Admin > Plugins, activate the new “FacetWP Schedule Indexer” plugin.

/*
Plugin Name: FacetWP Schedule Indexer
Plugin URI: https://facetwp.com/
Description: Runs indexer periodically by cron
Version: 1.0
Author: FacetWP, LLC
*/

add_action( 'fwp_scheduled_index', 'fwp_scheduled_index' );
function fwp_scheduled_index() {
  FWP()->indexer->index(); // Does a full re-index
}

register_activation_hook( __FILE__, 'fwp_schedule_indexer_activation' );
function fwp_schedule_indexer_activation() {
  if ( ! wp_next_scheduled( 'fwp_scheduled_index' ) ) {
    wp_schedule_event( time(), 'hourly', 'fwp_scheduled_index' ); // The event will run 'hourly'. Valid other values: 'daily' and 'twicedaily'. Or a custom schedule name (created with the 'cron_schedules' hook)
  }
}

register_deactivation_hook( __FILE__, 'fwp_schedule_indexer_deactivation' );
function fwp_schedule_indexer_deactivation() {
  wp_clear_scheduled_hook( 'fwp_scheduled_index' );
}

The plugin adds a WP-cron event that does a full re-index and runs on an hourly schedule. Other valid values for the schedule are daily and twicedaily. See the documentation for wp_schedule_event().

If you want to use a custom schedule, you can create your own with the cron_schedules filter. For example, you could add a half_hourly schedule with the following code. Add it to your (child) theme’s functions.php and make sure to replace hourly with half_hourly in the FacetWP Schedule Indexer plugin code above.

function my_custom_schedule( $schedules ) {
  $schedules['half_hourly'] = array(
    'interval' => 1800, // number of seconds in a half an hour
    'display' => __('Once Every Half Hour')
  );
  return $schedules;
}
add_filter( 'cron_schedules', 'my_custom_schedule' );

How to check the indexing cron schedule

If you want to check if your newly added custom schedule is working, or if the fwp_scheduled_index WP-Cron event is actually scheduled to run, you can check both with the WP Crontrol plugin.

FacetWP indexing: show indexer statsIf you created a custom schedule, like the half_hourly example above, that schedule should appear in the Cron Schedules tab. And in the Cron Events tab you can see when the next run is of the facetwp_indexer_cron event that is added by the above plugin.

After the cron event has run, you can also verify the last time the indexer has run by clicking the “Show indexer stats” option in the dropdown of the “Re-index” button, on the Settings > FacetWP admin page.

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 above scheduling plugin.

With FacetWP’s built-in WP-CLI indexing command options you can also do partial re-indexes of only specific posts, post types, 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 when the indexing process runs exactly, and at which frequency. In this approach, FacetWP’s automatic indexing can 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:

add_filter( 'facetwp_indexer_is_enabled', '__return_false' );

This can be useful if you are using WP-CLI or WP-Cron to trigger indexing, or if you want to (temporarily) pause automatic indexing when importing content.

It is also possible to disable automatic indexing for certain types of content.

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:

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.

<?php

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 );

See also