Hey developers! Are you looking for a smarter way to handle data deletion in your Laravel applications? Instead of permanently erasing records, what if you could just “hide” them, keeping them safe for future recovery or auditing?
That’s exactly what Soft Deletes are for.
This powerful Eloquent feature is a lifesaver in many projects, especially when combined with the dynamic magic of Livewire 3. In this guide, we’ll break down exactly what soft deletes are, how to implement them step-by-step, and how to manage them seamlessly in a Livewire component.
Let’s dive in!
What is a Soft Delete?
A soft delete is a way to “delete” a record without actually removing it from your database table.
When you perform a soft delete on a model, Laravel doesn’t run a DELETE SQL statement. Instead, it simply sets a timestamp on a special deleted_at column in that record’s row.
Once that deleted_at column is set, Laravel’s Eloquent ORM automatically filters that record out of all your queries. For your application, it’s gone. But for your database, it’s still there, just marked as inactive.
This is perfect for:
- Restoring accidentally deleted data.
- Maintaining a history of records for auditing.
- Preserving relationships with other tables.
How to Implement Soft Deletes in Laravel
Getting started with soft deletes is incredibly simple. It’s a two-step process.
Step 1: The Migration
First, you need to add the deleted_at column to your table. The easiest way is to use the softDeletes() helper method in your migration file when creating or altering a table.
Let’s imagine we have a products table.
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::create('products', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->decimal('price', 8, 2);
$table->timestamps();
$table->softDeletes(); // This adds the nullable `deleted_at` column
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('products');
}
};
Now, run your migration: php artisan migrate
Step 2: The Model
Next, you need to tell your Eloquent model to use the soft delete functionality. You do this by adding the SoftDeletes trait to the model class.
PHP
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes; // 1. Import the trait
class Product extends Model
{
use HasFactory, SoftDeletes; // 2. Use the trait
protected $fillable = [
'name',
'price',
];
}
And that’s it! Any time you call the delete() method on a Product model, it will now perform a soft delete.
Bringing it to Life with Livewire 3
Now for the fun part. Let’s create a dynamic interface to manage our products using Livewire 3, allowing a user to delete a product without a page refresh.
Here’s a simple component that lists products and has a delete button for each one.
The Livewire Component Class
PHP
<?php
// app/Livewire/ManageProducts.php
namespace App\Livewire;
use Livewire\Component;
use App\Models\Product;
use Livewire\Attributes\On; // Import the On attribute
class ManageProducts extends Component
{
// This will hold our collection of products from the database
public function getProductsProperty()
{
return Product::orderBy('name')->get();
}
// The delete method, which will be called from the frontend
public function delete($productId)
{
// Find the product by its ID
$product = Product::find($productId);
// If the product exists, delete it
if ($product) {
$product->delete(); // This performs the soft delete
}
// We don't need to manually refresh the list.
// Livewire will automatically re-render the component.
}
public function render()
{
return view('livewire.manage-products');
}
}
The Livewire View
This is the Blade file where we’ll display our table. Notice the wire:click and wire:confirm attributes—these are powerful Livewire features that make our component interactive.
HTML
<div>
<h3 style="margin-bottom: 1rem;">Product List</h3>
<style>
/* Simple styling for a clean table */
.product-table { width: 100%; border-collapse: collapse; }
.product-table th, .product-table td { border: 1px solid #ddd; padding: 8px; text-align: left; }
.product-table th { background-color: #f2f2f2; }
.delete-btn { background-color: #dc3545; color: white; border: none; padding: 5px 10px; border-radius: 4px; cursor: pointer; }
.delete-btn:hover { background-color: #c82333; }
</style>
<table class="product-table">
<thead>
<tr>
<th>Product Name</th>
<th>Price</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@forelse ($this->products as $product)
<tr wire:key="{{ $product->id }}">
<td>{{ $product->name }}</td>
<td>${{ number_format($product->price, 2) }}</td>
<td>
<button
class="delete-btn"
wire:click="delete({{ $product->id }})"
wire:confirm="Are you sure you want to delete this product?">
Delete
</button>
</td>
</tr>
@empty
<tr>
<td colspan="3">No products found.</td>
</tr>
@endforelse
</tbody>
</table>
</div>
Now, when a user clicks the “Delete” button, Livewire will show a confirmation dialog. If confirmed, it will call the delete() method in your component, which soft deletes the record. The component will then automatically re-render, and the product will disappear from the list—all without a single page reload!
Querying Soft Deleted Models
What if you need to see the “deleted” items? Eloquent provides handy methods for that:
withTrashed(): Get all records, including soft-deleted ones.PHP$allProducts = Product::withTrashed()->get();onlyTrashed(): Get only the soft-deleted records. This is great for building a “Trash” or “Recycle Bin” feature.PHP$deletedProducts = Product::onlyTrashed()->get();restore(): To bring a soft-deleted record back.PHPProduct::withTrashed()->find($productId)->restore();forceDelete(): To permanently delete the record. Use with caution!PHPProduct::withTrashed()->find($productId)->forceDelete();
Conclusion: To Soft Delete or Not?
Soft deletes are a fantastic tool in the Laravel ecosystem. They provide a safety net for data, maintain historical integrity, and are essential for applications that require auditing. Combined with Livewire, you can build a user-friendly and robust experience for managing data.
However, remember the trade-offs: they increase your database size and can add complexity to data privacy rules like GDPR. Always evaluate if they fit your project’s specific needs.
What are your thoughts? Do you use soft deletes in your projects? Share your experiences in the comments below!