Appearance
Customizing User Registration and Profiles
The default user registration page provided by our starter kit is functional but basic, capturing only the essential name, email, and password. In a real-world application, you'll often need to gather more information from users. This chapter will guide you through the process of enhancing the user registration and profile management system.
We will add a phone_number field to both the registration form and the user's profile page, allowing users to provide and later update this information. The techniques demonstrated here can be applied to add any number of custom fields to your user model.
Adding a Phone Number to the Database
Before we can add a field to our forms, we need to add a corresponding column to the users table in our database. There are two common approaches to modifying an existing table schema:
- Modify the original migration file: This is quick for initial development but is generally discouraged once a project is in production or shared with a team, as it can lead to inconsistencies.
- Create a new migration file: This is the recommended approach. It creates a new, timestamped file that describes the specific changes to be made. This method is version-control friendly and provides a clear history of database schema evolution.
We will use the second, more robust method.
Creating a New Migration
Laravel's Artisan command-line tool makes it simple to generate a new migration file tailored for modifying a specific table.
- Open your terminal in the project directory.
- Execute the
make:migrationcommand with the--table=usersoption to specify which table we are altering:
bash
php artisan make:migration add_phone_number_to_users_table --table=users1
This command creates a new migration file in your database/migrations directory, such as 2025_10_24_120000_add_phone_number_to_users_table.php. The file is pre-populated with a Schema::table() call.
- Open this new migration file.
- In the
up()method, we'll add a nullable string column calledphone_number. - In the
down()method, which defines how to reverse the migration, we'll drop that same column.
php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->string('phone_number')->nullable();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('phone_number');
});
}
};1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
- Now, run the migration to apply the changes to your database. The
--seedoption will also repopulate your database with initial data.
REMARK
Remember that the migrate:fresh command is destructive. It will drop all existing tables and re-run all migrations from scratch. This is fine for a development environment but should be used with caution on a production database.
bash
php artisan migrate:fresh --seed1
Updating the User Model
For security, Laravel protects against mass-assignment vulnerabilities by default. To allow our new phone_number field to be saved using methods like User::create(), we must explicitly add it to the $fillable array in the User model.
- Open the
app/Models/User.phpfile and add'phone_number'to the$fillableproperty.
php
protected $fillable = [
'name',
'email',
'password',
'active',
'admin',
'phone_number',
];1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
Adding the Phone Field to the Registration Page
With the database and model prepared, we can now modify the front-end registration form. This requires updating both the Livewire component's view and its corresponding PHP class.
- Open
resources/views/livewire/auth/register.blade.phpand add a new<flux:input>component for the phone number, placing it after the email field. - Open
app/Livewire/Auth/Register.phpto add the backend logic. We need to:- Add a public property
$phone_numberto bind to our new input field. - Add validation rules for this property. We'll make it optional (
nullable), but if provided, it must be a string that starts with a+and is followed by 11 to 15 digits (regex:/^\+\d{11,15}$/). - The
User::create($validated)call doesn't need to be changed. Livewire's$this->validate()method returns an array of all validated data, which now automatically includesphone_numberif it was provided and passed validation.
- Add a public property
php
<!-- Email Address -->
<flux:input
wire:model="email"
:label="__('Email address')"
type="email"
required
autocomplete="email"
placeholder="email@example.com"
/>
<!-- Phone Number -->
<flux:input
wire:model="phone_number"
:label="__('Phone Number')"
type="text"
icon="device-phone-mobile"
autocomplete="phone"
placeholder="+32479000000"
/>
<!-- Password -->1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Allowing Users to Update Their Phone Number
After registering, users should be able to view and modify their phone number on their profile page. The process is very similar to what we did for the registration page.
- app/Livewire/Settings/Profile.php:
- Add a public property
$phone_number. - In the
mount()method, initialize this property with the currently authenticated user's phone number. - In the
updateProfileInformation()method, add the same validation rule forphone_number.
- Add a public property
- resources/views/livewire/settings/profile.blade.php:
- Add a
<flux:input>field to the form, binding it to the$phone_numberproperty.
- Add a
php
class Profile extends Component
{
public string $name = '';
public $phone_number = '';
public string $email = '';
/**
* Mount the component.
*/
public function mount(): void
{
$this->name = Auth::user()->name;
$this->email = Auth::user()->email;
$this->phone_number = Auth::user()->phone_number;
}
/**
* Update the profile information for the currently authenticated user.
*/
public function updateProfileInformation(): void
{
$user = Auth::user();
$validated = $this->validate([
'name' => ['required', 'string', 'max:255'],
'phone_number' => 'nullable|regex:/^\+\d{11,15}$/',
'email' => [
'required',
'string',
'lowercase',
'email',
'max:255',
Rule::unique(User::class)->ignore($user->id),
],
]);
$user->fill($validated);
if ($user->isDirty('email')) {
$user->email_verified_at = null;
}
$user->save();
$this->dispatch('profile-updated', name: $user->name);
}
...
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
Optional: Managing the 'Delete Account' Feature
In some applications, you may not want users to be able to delete their own accounts, especially if they are administrators. You can easily control the visibility of the "Delete Account" section within the profile view.
Disabling Account Deletion for All Users
The simplest way to remove the feature entirely is to comment out or delete the Livewire component that renders the delete form.
- Open
resources/views/livewire/settings/profile.blade.php. - Comment out the
<livewire:settings.delete-user-form />line.
php
<section class="w-full">
@include('partials.settings-heading')
<x-settings.layout :heading="__('Profile')" :subheading="__('Update your name and email address')">
<form wire:submit="updateProfileInformation" class="my-6 w-full space-y-6">
...
</form>
{{-- <livewire:settings.delete-user-form /> --}}
</x-settings.layout>
</section>1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
Preventing Administrators from Deleting Their Account
A more nuanced approach is to conditionally display the delete form based on the user's role. We can use a simple Blade @if directive to check if the authenticated user is not an administrator.
- In the same file, wrap the
<livewire:settings.delete-user-form />component in a check for the user'sadminstatus.
php
<section class="w-full">
@include('partials.settings-heading')
<x-settings.layout :heading="__('Profile')" :subheading="__('Update your name and email address')">
<form wire:submit="updateProfileInformation" class="my-6 w-full space-y-6">
...
</form>
{{-- Show the delete button ONLY if the user is not an administartor --}}
@if (!auth()->user()->admin)
<livewire:settings.delete-user-form/>
@endif
</x-settings.layout>
</section>1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
This ensures that regular users can still delete their accounts, but the option will be hidden for any user with the admin flag set to true.