roots/wp-password-bcrypt
A WordPress plugin that replaces WordPress’s default password hashing with bcrypt using PHP’s password_hash and password_verify. Existing passwords are rehashed automatically on login, improving security without changing the user experience.
roots/wp-password-bcrypt is a WordPress plugin, not a Composer library — it is not installable via composer require and has no Laravel service provider. The only realistic entry point for a Laravel developer is a project where WordPress and Laravel share a wp_users table (legacy WP site being wrapped by a Laravel app, a Laravel admin panel over a WP database, or a headless WP install fronted by Laravel).
Before doing anything, read PR #52 ("Sunset package"). 1.3.0 is the release that formally ends the package's life. Treat this as an evaluation of an existing dependency, not a new adoption. If you are starting fresh, use Laravel's own Hash facade for your application users and let WordPress core handle its own hashing — do not add this plugin.
Minimal setup in a WP+WP context is a single drop-in:
wp-content/plugins/wp-password-bcrypt/wp-password-bcrypt.php
Activate it, then verify the first-use case that actually matters: an existing user logs in with their old MD5 password, the plugin validates it, and silently rewrites the row to a $2y$ bcrypt hash. Check the user_pass column before and after one login — that rehash-on-login behaviour is the whole value proposition.
Shared-table authentication from Laravel. If your Laravel app must authenticate WordPress users, do not use this plugin's internals — use Hash::check() against the user_pass column, since bcrypt hashes produced by this plugin are standard password_hash() output and are readable by Laravel's BcryptHasher. The reverse (WP verifying a Laravel-created hash) works only while the plugin is active, because core WP still expects phpass.
Custom guard example shape:
if (Hash::check($plain, $user->user_pass)) {
// optionally rehash into your own cost factor
if (Hash::needsRehash($user->user_pass)) {
$user->forceFill(['user_pass' => Hash::make($plain)])->save();
}
}
Action-hook integration (WP 6.7+). 1.3.0 adds the $old_user_data parameter to the wp_set_password action so it matches core's signature. If you hook wp_set_password to sync password changes into a Laravel-side audit log or notification queue, your callback must now accept the second argument:
add_action('wp_set_password', function ($password, $old_user_data) {
// $old_user_data is a WP_User object
}, 10, 2);
Callbacks registered with the old single-argument signature keep working (PHP ignores extra args for closures only if declared loosely — verify any strictly-typed callback), but anything that previously could not identify which user changed gets that ability now.
Detecting the migration state. For a cutover you will want a query like SELECT ID FROM wp_users WHERE user_pass NOT LIKE '$2y$%' AND user_pass NOT LIKE '$argon2%' to count users still on legacy hashes, and a policy for forcing a reset on the stragglers before you disable the plugin.
1.3.0 deliberately, add a ticket to migrate off, and do not build new features on top of it.SensitiveParameter attributes were added to $password and $hash. This means those values are redacted from stack traces. Good — but it also means any debugging or logging you wrote that relied on seeing the raw hash in an exception trace will silently stop showing it. Do not "fix" this by logging the password yourself.bcrypt.rounds. Hashes remain mutually verifiable, but Hash::needsRehash() will return true constantly if the costs differ, causing a write on every login. Align config/hashing.php before wiring the rehash loop above.user_pass column directly (seeders, imports, admin tools), write a Hash::make() value — never the legacy WP format. A mixed table is fine for reading, painful for cutover.wp_set_password hook ordering. It fires after the row is updated. If your Laravel sync callback reads $old_user_data to fan out a session-invalidation event, remember the DB already holds the new hash at that point.How can I help you explore Laravel packages today?