WordPress.org

Make WordPress Core

Opened 3 years ago

Last modified 2 years ago

#39829 new enhancement

Missing Filter before user is created within "wp_insert_user" function

Reported by: jaschaio Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version: 4.7.2
Component: Users Keywords:
Focuses: Cc:
PR Number:

Description

The "wp_insert_post" function has a filter called "wp_insert_post_data" that filters the post data right before the post is created.

For me the "wp_insert_user" function should have as well a filter right before the user is created in the database.

Unfortunately it doesn't exists. There is a action called "user_register" that lets me do something once the user is created, but it doesn't let me modify the actual data the "wp_insert_user" function returns.

Background:

I use the "wp_insert_post_data" filter to assign a random unique ID to each new post. This is helpful if you have a custom post type with sensitive data, where you don't want to make public how many exists or get created per day. (If the post ID is only auto increated each day, you could get this information by quering once in the morning and once in the night).

But it's impossible to assign a random unique ID to a newly created user. Or actually, it is not possible, I can hook into the "user_register" action and udpate all database tables with a new user id. But I can not use that new information as the "wp_insert_user" function will still return the old ID.

Change History (4)

#1 @SergeyBiryukov
3 years ago

  • Keywords reporter-feedback added

Hi @jaschaio, welcome to WordPress Trac! Thanks for the ticket.

There is a action called "user_register" that lets me do something once the user is created, but it doesn't let me modify the actual data the "wp_insert_user" function returns.

wp_insert_user() does not return user data though, just user ID on success or a WP_Error object on failure.

There are filters for individual fields and metadata, any reason they don't work for your use case?

  • pre_user_login
  • pre_user_nicename
  • pre_user_url
  • pre_user_email
  • pre_user_nickname
  • pre_user_first_name
  • pre_user_last_name
  • pre_user_display_name
  • pre_user_description
  • insert_user_meta

#2 @jaschaio
3 years ago

Hey @SergeyBiryukov, thanks for the fast reply. I have seen the other filters, but there is still no filter for the user ID.

As I explained: Within the wp_insert_post_data function you have the ability to filter through all the $data array. That means that you can modify the $data[ID] and assign a different one before the post gets actually inserted into the database.

Example:

/**
 * Filter to use random 6 digit number as post ID
 **/
function create_random_unique_id( $data, $postarr ) {

    // Check if we are updating an existing post or importing with a suggested post ID
    if ( ! empty( $postarr['ID'] ) || ! isset( $postarr['import_id'] ) ) {
        return $data;
    } else {
        // Get Wordpress Database
        global $wpdb;

        // Create random 6 digit number
        $random   = substr( rand() * 900000 + 100000, 0, 6 );

        // Check if ID is unique in database
        while ( $wpdb->get_var( $wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE ID = %d", $random ) ) ) {
            // Generate new random ID
            $random   = substr( rand() * 900000 + 100000, 0, 8 );
        }

        // Assign new post id random number
        $data['ID'] = $random;

        return $data;
    }

}
add_action( 'wp_insert_post_data', 'create_random_unique_id', 10, 2 );

The wp_insert_user function seems to work different, as it inserts the user first into the database based on the nickname (and not like the post based on the ID) and than works with the ID returned by the database going forward. Meaning that I can't hook in anywhere to change the ID of the to be created user. The only thing I can do is updating the database after the user is created with the user_register action. Here is an example for that:

function create_random_unique_user_id( $user_id ) {

    // Get global Wordpress Database Object
    global $wpdb;

    // Get newly created user ID
    $user_object = get_user_by( 'id', $user_id );

    // Create random 6 digit number
    $random   = substr( rand() * 900000 + 100000, 0, 6 );

    // Check if ID is unique in database
    while ( $wpdb->get_var( $wpdb->prepare("SELECT ID FROM $wpdb->users WHERE ID = %d", $random ) ) ) {
        // Generate new random ID
        $random   = substr( rand() * 900000 + 100000, 0, 8 );
    }

    // Update all tables with new user ID
    $wpdb->update( $wpdb->users, array( 'ID' => $random ), array( 'ID' => $user_id ) );
    $wpdb->update( $wpdb->posts, array( 'ID' => $random ), array( 'post_author' => $user_id ) );
    $wpdb->update( $wpdb->usermeta, array( 'ID' => $random ), array( 'user_id' => $user_id ) );
    $wpdb->update( $wpdb->comments, array( 'ID' => $random ), array( 'user_id' => $user_id ) );
    $wpdb->update( $wpdb->links, array( 'ID' => $random ), array( 'link_owner' => $user_id ) );

}
add_action( 'user_register', 'create_random_unique_user_id', 10, 1 );

But this is problematic as the user_id returned by wp_insert_user is still the old one. As such other functions who depend on the return value of wp_insert_user fail.

I just wondered why there are filters available for every other field of the user, but no one for the ID. Especially if its possible within the "wp_insert_post_data" function. These two should work similar.

Last edited 3 years ago by jaschaio (previous) (diff)

#3 @jaschaio
3 years ago

  • Keywords reporter-feedback removed

#4 @sc0ttkclark
2 years ago

I also am +1 on a filter before the user is created OR updated, just after the $data var is set.

Something like this?

	$data = wp_unslash( $compacted );

	/**
 	 * Filters a user's data values and keys before the user is created or updated.
 	 *
 	 * Does not include contact methods. These are added using `wp_get_user_contact_methods( $user )`.
 	 *
 	 * @since 4.8
 	 *
 	 * @param array $data {
 	 *     Default data values and keys for the user.
 	 *
 	 *     @type string $user_pass       The user's password.
	 *     @type string $user_email      The user's email.
	 *     @type string $user_url        The user's url.
	 *     @type string $user_nicename   The user's nicename.
	 *     @type string $display_name    The user's display name.
	 *     @type string $user_registered The user's registration date.
 	 * }
 	 * @param array $where {
 	 *     Values and keys used for identifying the user being inserted or updated.
 	 *
 	 *     @type int    $ID         The user's ID.
	 *     @type string $user_login The user's login.
 	 * }
 	 * @param array $meta {
 	 *     Default meta values and keys for the user.
 	 *
 	 *     @type string   $nickname             The user's nickname. Default is the user's username.
	 *     @type string   $first_name           The user's first name.
	 *     @type string   $last_name            The user's last name.
	 *     @type string   $description          The user's description.
	 *     @type bool     $rich_editing         Whether to enable the rich-editor for the user. False if not empty.
	 *     @type bool     $comment_shortcuts    Whether to enable keyboard shortcuts for the user. Default false.
	 *     @type string   $admin_color          The color scheme for a user's admin screen. Default 'fresh'.
	 *     @type int|bool $use_ssl              Whether to force SSL on the user's admin area. 0|false if SSL is
	 *                                          not forced.
	 *     @type bool     $show_admin_bar_front Whether to show the admin bar on the front end for the user.
	 *                                          Default true.
 	 * }
	 * @param bool  $update Whether the user is being updated rather than created.
 	 */
	$data = apply_filters( 'insert_user_data', $data, compact( 'ID', 'user_login' ), $meta, $update );

I think we should follow up with an additional ticket at some point that fixes the text of the insert_user_meta filter does not describe as "before the user is created or updated" -- it should actually be "after the user has been created or updated". Right now, the hook description is problematic and misinforming to developers.

Note: See TracTickets for help on using tickets.