Make WordPress Core

Opened 9 years ago

Last modified 5 months ago

#39370 new defect (bug)

wp_insert_user() appends suffix to nicename when updating already existing user

Reported by: alfhen's profile alfhen Owned by:
Milestone: Future Release Priority: normal
Severity: normal Version: 4.6.1
Component: Users Keywords: reporter-feedback has-patch needs-unit-tests needs-test-info
Focuses: Cc:

Description

wp_insert_user() appends suffix to nicename when updating already existing user, even though the user_nicename prop is set to exactly the same value as it currently has.

Steps to reproduce:

  • Asuming you have a user in your wordpress database with the ID 1 and user_nicename set to 'test-nicename'.
  • If you then make an update using wp_insert_user() of that user and in the update set the user_nicename to 'test-nicename', then wordpress will update the user, but append -2 as a suffix to the nicename.

This happens because of a check located on line 1597 - 1609 in wp-includes/user.php

<?php
$user_nicename_check = $wpdb->get_var( $wpdb->prepare("SELECT ID FROM $wpdb->users WHERE user_nicename = %s AND user_login != %s LIMIT 1" , $user_nicename, $user_login));

        if ( $user_nicename_check) {
                $suffix = 2;
                while ($user_nicename_check) {
                        // user_nicename allows 50 chars. Subtract one for a hyphen, plus the length of the suffix.
                        $base_length = 49 - mb_strlen( $suffix );
                        $alt_user_nicename = mb_substr( $user_nicename, 0, $base_length ) . "-$suffix";
                        $user_nicename_check = $wpdb->get_var( $wpdb->prepare("SELECT ID FROM $wpdb->users WHERE user_nicename = %s AND user_login != %s LIMIT 1" , $alt_user_nicename, $user_login));
                        $suffix++;
                }
                $user_nicename = $alt_user_nicename;
        }

This code is there to make sure that there are no duplicate nicenames in the wp_users table, which is fine. However it does not take into account updating the nicename of a user with the same value as it currently has.

The way to solve it is very easy, only simply changes the if() statement to check the id fethced in $user_nicename_check against the ID of the user currently being updated, like so:

<?php
$user_nicename_check = $wpdb->get_var( $wpdb->prepare("SELECT ID FROM $wpdb->users WHERE user_nicename = %s AND user_login != %s LIMIT 1" , $user_nicename, $user_login));

        if ( $user_nicename_check && $ID != $user_nicename_check) {
                $suffix = 2;
                while ($user_nicename_check) {
                        // user_nicename allows 50 chars. Subtract one for a hyphen, plus the length of the suffix.
                        $base_length = 49 - mb_strlen( $suffix );
                        $alt_user_nicename = mb_substr( $user_nicename, 0, $base_length ) . "-$suffix";
                        $user_nicename_check = $wpdb->get_var( $wpdb->prepare("SELECT ID FROM $wpdb->users WHERE user_nicename = %s AND user_login != %s LIMIT 1" , $alt_user_nicename, $user_login));
                        $suffix++;
                }
                $user_nicename = $alt_user_nicename;
        }

This makes prevents the code from appending the suffix when the $user_nicename_check ID matches the ID of the user currently being updated

Attachments (2)

39370.patch (636 bytes) - added by alfhen 9 years ago.
Patch with the mentioned fix
39370.1.diff (1.4 KB) - added by azaozz 6 years ago.

Download all attachments as: .zip

Change History (10)

@alfhen
9 years ago

Patch with the mentioned fix

#1 @chanthaboune
6 years ago

  • Milestone changed from Awaiting Review to 5.4

#2 @donmhico
6 years ago

  • Keywords reporter-feedback added

Hello @alfhen,

Welcome in WordPress trac! I know that this ticket is quite old now but I'm having difficulties to reproduce the problem.

Using wp_insert_user() without ID param and with user_nicename that already exists will create a new user with suffixed user_nicename.

Using wp_insert_user() with ID and with user_nicename that's the same as the current user's user_nicename will update the user info properly. user_nicename isn't suffixed.

In short, I can't seem to find a way to use wp_insert_user() that updates the an existing user that also suffixed the user_nicename. If you can give the exact wp_insert_user() code you use to produce the problem, it will definitely help.

Thank you!

This ticket was mentioned in Slack in #core by david.baumwald. View the logs.


6 years ago

#4 @davidbaumwald
6 years ago

  • Milestone changed from 5.4 to Future Release

With 5.4 Beta 3 landing tomorrow, this is being moved to Future Release. If any maintainer or committer feels this can be resolved in time or wishes to assume ownership during a specific cycle, feel free to update the milestone accordingly.

#5 @azaozz
6 years ago

As far as I see this can happen when the $user_login has been changed. This cannot happen in core by default ($user_login is not changeable), but can be added/enabled by a plugin.

Then the DB query will "find" a user ID as the updated $user_login hasn't been saved yet. So using the $user_login to confirm if it is the same user doesn't work. Would be better to use the user ID for that.

Last edited 6 years ago by azaozz (previous) (diff)

@azaozz
6 years ago

#6 @azaozz
6 years ago

  • Keywords has-patch needs-testing needs-unit-tests added

In 39370.1.diff: Instead of the user login use the user ID when checking whether a user nicename belongs to the same user.

Version 0, edited 6 years ago by azaozz (next)

This ticket was mentioned in PR #9055 on WordPress/wordpress-develop by @SirLouen.


5 months ago
#7

Refreshing patch for testing.

Trac ticket: https://core.trac.wordpress.org/ticket/39370

#8 @SirLouen
5 months ago

  • Keywords needs-test-info added; needs-testing removed

Bug Reproduction Report

Description

❌ This report can't validate that the issue can be reproduced.

Environment

  • WordPress: 6.9-alpha-60093-src
  • PHP: 8.2.28
  • Server: nginx/1.27.5
  • Database: mysqli (Server: 8.4.5 / Client: mysqlnd 8.2.28)
  • Browser: Chrome 137.0.0.0
  • OS: Windows 10/11
  • Theme: Twenty Twenty 2.9
  • MU Plugins: None activated
  • Plugins:
    • Change Username 1.0.2
    • Test Reports 1.2.0

Testing Instructions

  1. Use the code provided in supplemental artifacts somewhere you can execute it. For example, you can create a standalone file loading wp-load.php and hard-code a user id and a username and pass both to the function.
  2. Execute the code twice. First time it will set the username you selected correctly.
  3. ❌ Second time, the nicename is preserved identically

Actual Results

  1. ❌ Issue can't be reproduced

Additional Notes

  • The idea of @azaozz to using a plugin for changing the username was good on paper… but obviously, if they wanted to have a functional plugin, they would not be using this route. For example, this plugin, directly do the edits through SQL. For this reason, I built a little plugin to mimic this job.
  • Maybe this has been solved at some point? Please review the code proposed and the steps and see if I'm missing something to report back.
  • I refreshed the patch thinking that I could easily reproduce this bug, but I couldn't. In case someone gives new testing instructions, perhaps that patch could sort the potential problem.

Supplemental Artifacts

Testing base code:

function change_username( $user_id, $new_username ) {

    $user_data = array(
        'ID'         => $user_id,
        'user_login' => $new_username,
    );

    return wp_insert_user( $user_data );
}

$user_id = 1
$new_username = 'test-nicename'
change_username( $user_id, $new_username );
Note: See TracTickets for help on using tickets.