This plugin lets you connect users to a post type, so that you can create user listings, and filter users like any other post type.

How it works

FacetWP can only index and filter posts (of any (custom) post type). However, WP users are not a post type, so users cannot be filtered directly. To make users filterable by FacetWP, this add-on creates a new (hidden) upt_user custom post type, and adds a post for each WP user.

The add-on’s settings also let you sync user data to the new upt_user post type. This data can then be used when setting up facets that can filter users, or to customize user queries with a meta_query. The synced user data consists of the default user data that is available by for each WP user, but also custom (user) fields that are added with other plugins. The add-on supports custom fields made with BuddyPress and Advanced Custom Fields. See this example to learn how to add custom user fields with Advanced Custom Fields.

Despite the upt_user custom post type not being directly visible in the WP admin menu, you can still access it to see and check all synced users and their custom fields.

Getting started

Download

Download the add-on from your account and install it as a plugin.

Setup

Here is a short video on how to set up the add-on:

How to sync users.
How to sync users.

After installing and activating the add-on, browse to Settings > User Post Type and click the “Sync now” button.

As seen in the image on the right, you can also copy extra custom user fields (other than the default user fields) into the wp_postmeta table. This is not required to display that custom field data or to use those custom fields as a facet’s data source. Syncing extra custom user fields is only useful/needed if you use these fields in a meta_query in a custom WP_Query, as demonstrated in the examples below.

Here’s a list of dropdown choices and corresponding meta_query keys:

Option Meta Key
User ID ID
User Login user_login
User Email user_email
User URL user_url
Registration Date user_registered
User Status user_status
Display Name display_name
Roles roles
Usermeta field meta-[fieldname]
Field keys are prefixed with meta- when synced. So if you make a custom user field with Advanced Custom Field, the field name to use in a custom meta query is meta-[fieldname]. See the example below.
BuddyPress field bp-[fieldID]
Field IDs are prefixed with bp- when synced.

How to see and check synced users and custom fields

The hidden upt_user custom post type that this add-on generates is not directly visible in the WP admin menu, but you can still access its overview screen by using this URL:

https://yourdomain.com/wp-admin/edit.php?post_type=upt_user
The (hidden) UPT Users overview screen. Use 'Edit' to see the custom user fields. Hover over 'View' to see the WP user ID in the /user-x/ URL in the browser's status bar.
The (hidden) UPT Users overview screen. Use “Edit” to see the custom user fields. Hover over “View” to see the WP user ID in the /user-x/ URL in the browser’s status bar.

In this UPT Users overview screen, you can see all synced users. These upt_user posts have a post URL ending in /user-x/, where x corresponds with the WP user ID. If needed, you can use this ID to check for discrepancies after syncing. This post URL can be seen by hovering over the “View” link under the post item, as shown in the image on the right.

If you click the “Edit” link of a upt_user post/user, you can also see all synced custom fields and their values.

If the Custom Fields metabox does not show up, you probably have Advanced Custom Fields installed, which by default hides this metabox. To enable the metabox, add the following ACF hook 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( 'acf/settings/remove_wp_meta_box', function( $remove ) { if ( ! is_admin() || ! function_exists( 'get_current_screen' ) ) { return $remove; } $screen = get_current_screen(); if ( $screen->base === 'post' && $screen->post_type === 'upt_user' ) { return false; // Re-enable the Custom Fields metabox } return $remove; }, 20 );

Query all users

To display a list of all users, use WP_Query (not WP_User_Query ) like so:

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 = [ 'post_type' => 'upt_user', 'post_status' => 'publish', 'posts_per_page' => 10, ]; $query = new WP_Query( $args );

You can also use a Listing Builder listing, or for more elaborate queries, a Listing Builder listing in Dev mode, as shown below.

Query a subset of users

To query a subset of users, you need to create a custom WP_Query that uses meta_query to filter by existing user fields or by custom user fields.

Query users by existing user fields with a meta query

To display only administrators, select “Roles” in the settings page dropdown, then click the blue “Sync now” button. Then you can use the roles field within meta_query:

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 = [ 'post_type' => 'upt_user', 'post_status' => 'publish', 'orderby' => [ 'title' => 'ASC' ], 'posts_per_page' => 30, 'meta_query' => [ [ 'key' => 'roles', 'value' => 'administrator', 'compare' => '=', ] ] ]; $query = new WP_Query( $args );

To do same with multiple roles, in this example administrators and editors:

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 = [ 'post_type' => 'upt_user', 'post_status' => 'publish', 'orderby' => [ 'title' => 'ASC' ], 'posts_per_page' => 30, 'meta_query' => [ [ 'key' => 'roles', 'value' => [ 'administrator', 'editor' ], 'compare' => 'IN', ] ] ]; $query = new WP_Query( $args );

Query users by one or more custom user fields with a meta query

Say you want to give users a custom status field, and you want to display a user listing that excludes users with a specific status.

To accomplish this, let’s first create the custom status field and attach it to WP’s user profile page.

Using Advanced Custom Fields, create a field group for your user field(s) and set its “Location Rules” to “User Form -> is equal to -> All”, as shown in the image below. Next, create a new custom field in this field group, e.g. my_user_status. You can add more fields later.

How to create a custom user field with Advanced Custom Fields.
How to create a custom user field with Advanced Custom Fields.

Next, go to Settings > User Post Type, and in the dropdown select the field name my_user_status. You’ll also see one prefixed with an underscore (_my_user_status), which you can ignore. Click Save, then click the blue “Sync now” button.

After syncing, the new custom field is now available to use in a meta_query argument if you query the upt_user post type, as demonstrated below. Note that you need to make sure all WP users are saved after adding the new field, because otherwise they will not have the field in their postmeta and querying by it will not work as expected.

Now everything is ready to create a user listing query that uses the new user status field. In the following example, we’ll use the Listing Builder in Dev mode, but you can do this in any other listing template type.

Create a new Listing Builder listing and set the “Display” tab to display whatever user data you want. For testing, just use “Display Name” or “Post Title” (which both output the user name). In the “Query” tab, enable “Dev mode” in the top right, and paste the following query arguments:

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

<?php return [ "post_type" => ["upt_user"], "post_status" => ["publish"], "meta_query" => [ "relation" => "AND", // State the relation if you use multiple meta queries [ "key" => "roles", // Roles is an existing WP field "compare" => "NOT IN", // Field EXISTS and is NOT IN ... "value" => ["practitioner"], // array of values "type" => "CHAR", ], [ "key" => "meta-my_user_status", // IMPORTANT: Use meta-[fieldname] and make sure the field is synced in UPT settings "compare" => "NOT IN", // Field EXISTS and is NOT IN ... "value" => ["expired"], // array of values "type" => "CHAR", ] ], "orderby" => "meta_value", // Order by the meta key specified in 'meta_key' "meta_key" => "display_name", // The meta key to sort by "order" => "ASC", "posts_per_page" => 20 ];

In the above example we retrieve upt_user posts that do NOT have the practioner role AND for which the my_user_status field the value is NOT expired. We order the listing by the user display_name, in ascending order (A-Z), and retrieve 20 posts per page.

Important to notice is that in line 14 we use meta-my_user_status, and not my_user_status. This is because when syncing WP user fields to the upt_user post type, all ACF custom fields are prefixed with meta-.

Display user fields

UPT supports WP’s get_user_meta() function. Just replace $user_id with UPT()->get_user_id():

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

echo get_user_meta( UPT()->get_user_id(), 'your_field_name', true );

Outside of The Loop, pass in the post ID like so:

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

echo get_user_meta( UPT()->get_user_id( THE_POST_ID ), 'your_field_name', true );

To get a user’s photo, you can use WP’s get_avatar() function, assuming that the image is stored in WP’s default “Profile Picture” field:

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

echo get_avatar( UPT()->get_user_id( THE_POST_ID ), 150 );

Add facets that filter by a user field

When creating a new facet, via Settings > FacetWP, you’ll see a new “User Fields” section in the Data source dropdown.

Finding a user’s associated post

Use the following if you have a $user_id and want to find the $post_id of the associated post:

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 = (int) get_user_meta( $user_id, UPT()->meta_key, true );

Prevent a specific user from being synced

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( 'upt_sync_skip_user', function( $bool, $user_id ) { if ( 1 === $user_id ) { return true; } return $bool; }, 10, 2 );

Prevent users with specific roles from being synced

To prevent users with a specific role from being synced, you can use the following snippet. Change the roles to be skipped in the array in line 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( 'upt_sync_skip_user', function( $bool, $user_id ) { $roles = (array) get_user_by( 'ID', $user_id )->roles; $roles_to_skip = [ 'dormant-student', 'dormant-teacher' ]; // Skip these roles foreach ( $roles_to_skip as $role ) { if ( in_array( $role, $roles ) ) { return true; // Do not sync this user } } return $bool; }, 10, 2 );

This also works for custom user roles made with a plugin, like for example User Role Editor.

You can also do the opposite:

Only sync users with a specific role

To sync only users with a specific role, you can use the following snippet. Change the roles to be synced in the array in line 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( 'upt_sync_skip_user', function( $bool, $user_id ) { $roles = (array) get_user_by( 'ID', $user_id )->roles; $roles_to_preserve = [ 'student','teacher' ]; // Sync only these roles $intersect = array_intersect( $roles, $roles_to_preserve ); if ( empty( $intersect ) ) { return true; // Do not sync this user } return $bool; }, 10, 2 );

Perform post-sync actions

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_action( 'upt_sync_post', function( $post_id, $user_id ) { // do something after a user is synced }, 10, 2 );

Force only certain users to be indexed

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( 'upt_sync_where', function( $where ) { $where = ' AND u.ID IN (1, 2, 3, 4, 5)'; return $where; });

Force a user sync on a schedule

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_action( 'mysite_sync_users', 'mysite_sync_users_callback' ); function mysite_sync_users_callback() { UPT()->sync->run_sync(); } if ( ! wp_next_scheduled( 'mysite_sync_users' ) ) { wp_schedule_single_event( time() + 28800, 'mysite_sync_users' ); // 28800 seconds = every 8 hours }

Force a single user sync

To manually sync a single user, use this in your code or 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

UPT()->sync->run_sync( $user_id );

Note that users are already synced automatically when their profile is updated from the standard wp-admin user profile editor.

Updating the profile triggers WordPress’ profile_update action hook that the User Post Type add-on uses to trigger the sync. Manual syncing would only be needed if updating a user’s profile is done in a way that does not trigger this hook.

Customize register_post_type arguments for the upt_user post type

You can use the upt_post_type_args hook to customize any arguments of the register_post_type function, when the upt_user post type is registered.

Two examples:

Force the admin menu to appear

To force the “UPT Users” admin menu to appear:

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( 'upt_post_type_args', function( $args ) { $args['show_in_menu'] = true; return $args; });

Prevent single upt_user posts from being visible

To prevent the single posts from the upt_user post type from being accessed on the front-end (via for example https://yourdomain.com/upt_user/user-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( 'upt_post_type_args', function( $args ) { $args['publicly_queryable'] = false; return $args; });

Customize access to the settings

If you need to give certain user roles access to the User Post Type add-on settings, you can use the upt_admin_settings_capability hook.

To change access to the main FacetWP plugin settings, and other add-ons, you can use the facetwp_admin_settings_capability hook.

Changelog

0.8.1Dec 16, 2024

  • New added `upt_admin_settings_capability` hook

0.8Aug 19, 2024

  • Fixed adjust sync priority to improve 3rd party compatibility

0.7.8Feb 26, 2024

  • Fixed PHP 8.2 deprecation notices
  • Fixed potential name conflict when re-indexing

0.7.7Feb 23, 2022

  • Fixed issue preventing value of "0" from getting indexed

0.7.6Nov 2, 2021

  • Important Go into `Settings > User Post Type` and hit the "Sync" button
  • Fixed issue causing a new meta row to get added on each user save

0.7.5Sep 10, 2021

  • Fixed sync issues (prevents needing to manually re-sync in many cases)

0.7.4Jun 8, 2021

  • New added `upt_sync_where` hook to customize the SQL WHERE clause

0.7.3Oct 29, 2020

  • New added multisite support (only sync users of the current site)

See also

Last updated: May 27, 2025