How to Add Laravel Livewire Checkout to Product Booking System (Part 2)

Learn how to build a Laravel Livewire checkout system for product booking cart. Step-by-step guide with database, Livewire component, and order storage.

In Part 1, we built a complete Product Booking System with Cart using Laravel Livewire, where users could:

  • Select a product
  • Choose a booking date
  • Select quantity
  • Add multiple products to cart
  • Merge identical cart entries

Now in Part 2, we will extend that system and add Laravel Livewire Checkout Form to make it fully working, where:

✔ User enters billing details
✔ Cart items are validated
✔ Orders are saved in database
✔ Cart clears after successful checkout
✔ Ready for payment integration

Let’s build it step-by-step.


Step 1: Create Order Tables

When a user places an order, we must store:

  • Who placed the order
  • Their contact details
  • The total order amount

Instead of saving everything in one table, we follow proper e-commerce structure and create 2 tables as follows:

  • orders: To store contact details and order related information
  • order_items: To store multiple order items for the order

This keeps your database clean and scalable.

Use the following migration command to create orders table:

php artisan make:migration create_orders_table

It will create a migration file xxxx_xx_xx_xxxxxx_create_orders_table.php inside database/migrations folder. Open this file and add the following code:

Schema::create('orders', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email');
$table->string('phone');
$table->text('address');
$table->decimal('total_amount', 10, 2);
$table->timestamps();
});

Similarly, use the same artisan command to create order_items table as follows,

php artisan make:migration create_order_items_table

And copy the following code to the generated migration file xxxx_xx_xx_xxxxxx_create_order_items_table.php:

Schema::create('order_items', function (Blueprint $table) {
$table->id();
$table->foreignId('order_id')->constrained()->cascadeOnDelete();
$table->foreignId('product_id');
$table->date('booking_date');
$table->integer('quantity');
$table->decimal('price', 10, 2);
$table->decimal('total', 10, 2);
$table->timestamps();
});

After both migrations, run the below migrate command to execute created migrations:

php artisan migrate

Step 2: Create Checkout Livewire Component

Create a checkout form livewire component using the following artisan command:

php artisan make:livewire CheckoutForm

It will create 2 files for product booking,

  • Class File: app/Livewire/CheckoutForm.php
  • Blade File: resources/views/livewire/checkout-form.blade.php

Livewire Component Logic

Open app/Livewire/CheckoutForm.php file and copy the following component login in it.

namespace App\Livewire;

use App\Models\Order;
use App\Models\OrderItem;
use App\Services\CartService;
use Livewire\Component;

class CheckoutForm extends Component
{
    public $name, $email, $phone, $address;

    protected $rules = [
        'name'    => 'required|string|min:3',
        'email'   => 'required|email',
        'phone'   => 'required',
        'address' => 'required|min:10',
    ];

    public function placeOrder()
    {
        $this->validate();

        $cart = CartService::all();

        if (empty($cart)) {
            session()->flash('error', 'Cart is empty!');
            return;
        }

        $total = array_sum(array_column($cart, 'total'));

        $order = Order::create([
            'name'         => $this->name,
            'email'        => $this->email,
            'phone'        => $this->phone,
            'address'      => $this->address,
            'total_amount' => $total,
        ]);

        foreach ($cart as $item) {
            OrderItem::create([
                'order_id'     => $order->id,
                'product_id'   => $item['product_id'],
                'booking_date' => $item['date'],
                'quantity'     => $item['quantity'],
                'price'        => $item['price'],
                'total'        => $item['total'],
            ]);
        }

        CartService::clear();

        return redirect()->route('order.success');
    }

    public function render()
    {
        return view('livewire.checkout-form', [
            'cart' => CartService::all()
        ]);
    }
}

Blade View with Message

Add the following code to the resources/views/livewire/checkout-form.blade.php.

<div class="row">

    <div class="col-md-7">
        <h4>Billing Details</h4>

        <input type="text" wire:model="name" placeholder="Full Name" class="form-control mb-2">
        <input type="email" wire:model="email" placeholder="Email" class="form-control mb-2">
        <input type="text" wire:model="phone" placeholder="Phone" class="form-control mb-2">
        <textarea wire:model="address" placeholder="Address" class="form-control mb-3"></textarea>

        <button wire:click="placeOrder" class="btn btn-success w-100">
            Place Order
        </button>
    </div>

    <div class="col-md-5">
        <h4>Order Summary</h4>

        @foreach($cart as $item)
            <div class="border-bottom mb-2 pb-2">
                {{ $item['name'] }} <br>
                Date: {{ $item['date'] }} <br>
                Qty: {{ $item['quantity'] }} <br>
                ₹{{ $item['total'] }}
            </div>
        @endforeach

        <h5 class="mt-3">
            Total: ₹{{ array_sum(array_column($cart, 'total')) }}
        </h5>
    </div>

</div>

It contains user details form with Place Order button to complete the order and Cart Summary with all items and total amount to be payed.

Apply CSS according to your project requirements and you can also add more fields to the checkout form.


Step 3: Add Checkout Route

Add a route to routes/web.php file as follows and point to checkout view.

Route::get('/checkout', function () {
return view('checkout');
})->name('checkout');

Route is point to checkout view. So, create resources/views/checkout.blade.php file and copy the following content to it:

@extends('layouts.app')@section('content')
<div class="container py-5">
<livewire:checkout-form />
</div>
@endsection

Checkout form livewire component is attached in above view file.


What Happens Now?

When user clicks Place Order the following process is being done inside CheckoutForm.php

  1. It validates billing data and creates order record.
  2. It retrieves cart items from session and save them to order items table.
  3. It clears the cart and redirects the user to success page.

You now have a fully working product booking checkout system in Laravel Livewire.


Optional Enhancements

To make this production-ready, you can add:

  • Integrate Stripe / Razorpay payment gateway for actual payment
  • Send email confirmation to admin as well as user
  • Generate invoice on place order or after payment complete or after mark order completed from admin panel.
  • Create order panel using filament to list all orders
  • Order status management

Cloudways WordPress Hosting Review (2026) – Why I Switched & Never Looked Back

Thinking of switching hosting? I moved my WordPress site to Cloudways and the speed boost shocked me. Read my honest review before you decide.

Choosing the right hosting is the single most important decision for your WordPress site. After years of hopping between cheap shared hosts and overly complex VPS setups, I finally moved my entire portfolio to Cloudways.

If you are tired of slow loading times, random downtimes, and limited “shared” resources, this guide is for you. I’m going to walk you through exactly why I use Cloudways and how it can transform your site’s performance.


Why I Switched to Managed Cloud Hosting

Traditional shared hosting is like living in an apartment building where your neighbors can hog the water and electricity. If their site gets a traffic spike, yours slows down.

Cloudways is different. It’s a managed layer that sits on top of the world’s best cloud providers (DigitalOcean, AWS, and Google Cloud). You get the raw power of a dedicated cloud server without needing to be a systems engineer.

1. Blazing Fast Performance (The “VMAN” Stack)

The first thing I noticed after migrating was my Core Web Vitals. Cloudways uses a unique optimization stack they call VMAN:

  • Varnish & Memcached: Advanced caching that serves pages instantly.
  • Apache & Nginx: A dual-webserver setup that balances power and speed.
  • Redis: Optional object caching that makes your WordPress dashboard feel snappy.

Since switching, my average page load time dropped from 3.2 seconds to under 800ms.

2. Choose Your Cloud Provider

Unlike other hosts that force you onto their proprietary hardware, Cloudways lets you choose your “engine.”

  • DigitalOcean: My personal favorite for value and speed (starts at ~$11/mo).
  • AWS & Google Cloud: Perfect for enterprise-level sites that need global reach.

3. Ironclad Security Without the Headache

As someone who has dealt with site hacks in the past, security is a non-negotiable for me. Cloudways includes:

  • Dedicated Firewalls: Built-in protection at the server level.
  • Bot Protection: Powered by MalCare to block brute-force attacks.
  • 1-Click Free SSL: You can install Let’s Encrypt SSL certificates in seconds.
  • Automated Backups: I have mine set to back up every 24 hours, so I never worry about losing data.

The Features That Make Management Easy

Cloudways isn’t just about speed; it’s about saving time. Here are the tools I use every week:

1-Click Staging Environment

I never test new plugins or themes on my live site. With Cloudways, I click “Create Staging,” make my changes on a “clone” of my site, and then push them live once I’m sure nothing is broken.

Vertical Scaling

If your site goes viral, you don’t need to migrate to a new plan. You simply move a slider in the dashboard to increase your RAM or CPU instantly. When the traffic dies down, you can scale back (on some providers) or keep the power.

SafeUpdates for WordPress

This is a game-changer. Cloudways can automatically update your WordPress core, plugins, and themes. The best part? It takes a screenshot of your site before and after the update; if it detects a visual break, it automatically rolls back the update.


Pricing: Pay-As-You-Go

The most “honest” part of Cloudways is the billing. There are no expensive 3-year contracts.

  • Monthly or Hourly Billing: You only pay for the hours your server was active.
  • No Hidden Upsells: Backups and security are baked into the price.

Pro Tip: Start with a 1GB or 2GB DigitalOcean Premium droplet. It’s incredibly fast and costs less than a few cups of coffee per month.


Final Verdict: Is Cloudways Right For You?

If you are running a serious business, a high-traffic blog, or an eCommerce store, yes. The time you save on technical maintenance and the SEO boost you get from the speed more than pays for the hosting.

How to Get Started:

  1. Sign up for a 3-Day Free Trial (No credit card required).
  2. Launch your server: Select DigitalOcean and your closest data center.
  3. Use the Migration Plugin: Cloudways provides a free plugin that moves your site for you automatically.

Rank Math SEO Review 2026: Is It the Best WordPress SEO Plugin? (Free vs Pro Comparison)

Is Rank Math Pro worth buying? Read our detailed 2026 Rank Math review with features, pricing and pros & cons.

If you run a WordPress website and want more traffic from Google, you need a powerful SEO plugin.

But with so many options available, the big question is:

👉 Is Rank Math better than Yoast SEO?
👉 Is Rank Math Pro worth buying in 2026?

In this detailed review, I’ll explain:

  • Rank Math features
  • Free vs Pro comparison
  • Pricing
  • Real benefits
  • Whether it’s worth your money

What is Rank Math?

Rank Math is a powerful WordPress SEO plugin that helps optimize your website for search engines like Google.

It provides:

  • On-page SEO suggestions
  • Keyword optimization
  • Schema markup
  • XML sitemaps
  • 404 monitoring
  • Redirection manager
  • AI content suggestions (Pro)

It’s currently used by 2+ million WordPress websites.


Why Rank Math is Popular in 2026

Here’s why bloggers and affiliate marketers prefer Rank Math:

Easy Setup Wizard

Beginner-friendly setup in less than 10 minutes.

Multiple Keyword Optimization (Free)

Unlike many plugins, Rank Math allows optimizing for multiple keywords in the free version.

Built-in Schema Generator

Add:

  • FAQ schema
  • Product schema
  • Article schema
  • Review schema

Without extra plugins.

Advanced Analytics Dashboard

It integrates with:

  • Google Search Console
  • Google Analytics

You can see keyword rankings inside WordPress.


Rank Math Free vs Pro (Comparison Table)

FeatureFreePro
Multiple Focus Keywords
Advanced Schema Builder
Keyword Rank Tracker
Content AI
404 Monitor
Redirection Manager
WooCommerce SEOLimitedFull

👉 If you run a serious blog or affiliate website, Pro is highly recommended.


Rank Math Pro Pricing (2026 Updated)

Rank Math Pro plans start around:

  • Pro – For bloggers
  • Business – For agencies
  • Agency – For large-scale projects

🔥 Limited-time discount available here:
👉 Get Rank Math Pro at 30% OFF:


Who Should Buy Rank Math Pro?

Rank Math Pro is ideal for:

✔ Affiliate marketers
✔ Bloggers
✔ WooCommerce store owners
✔ SEO agencies
✔ Niche website builders

If you are serious about ranking on Google and increasing traffic, Pro is worth the investment.


Real Benefits for Affiliate Bloggers

If you monetize through:

  • Hosting affiliate links
  • SaaS tools
  • Amazon products
  • Digital courses

Rank Math helps you:

  • Add review schema (increase CTR)
  • Track keyword rankings
  • Optimize product pages
  • Fix SEO errors instantly

This directly increases:
📈 Traffic
📈 CTR
📈 Affiliate revenue


Pros and Cons

✅ Pros

  • Powerful free version
  • Affordable Pro
  • Advanced schema
  • Built-in rank tracking
  • Lightweight

❌ Cons

  • Too many features for beginners
  • Some AI features cost extra credits

Final Verdict: Is Rank Math Worth It?

Yes.

If you want:

  • More traffic
  • Better rankings
  • Higher affiliate income
  • Advanced SEO tools in one plugin

👉 Rank Math Pro is absolutely worth buying in 2026.

🔥 Special Discount Link:

Build a Product Booking System with Cart Using Laravel Livewire

Learn how to build a complete Laravel Livewire v3 product booking system with date selection, quantity controls, cart merging, and a real-time sidebar cart. Step-by-step code included.

If you run an online store that sells products requiring date-based booking (for example rental products, events, workshops, or personalized items), then having a dynamic booking form with an integrated cart is essential. In this guide, you will learn how to build a complete Product Booking System + Cart using Laravel Livewire, where users can:

  • Select a product
  • Choose a date (mandatory)
  • Select quantity with + / – controls
  • Add multiple products to a single cart
  • Automatically merge identical items (same product + same date)
  • View the cart in a real-time sidebar

This is a fully working solution you can directly implement in your Laravel application.

Step 1: Update Your Database Structure

Create your products table:

Schema::create('products', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->text('description')->nullable();
    $table->decimal('price', 10, 2);
    $table->timestamps();
});

Step 2: Add Route for Product Details

Add a route to display products page, where we can display cart booking system,

Route::get('/products/{product}', function (\App\Models\Product $product) {
    return view('product-details', compact('product'));
})->name('product.details');

Step 3: Create Cart Service

Create a service app/Services/CartService.php to handle cart related actions from anywhere. This service simplifies the process to handle cart with session.

namespace App\Services;

class CartService
{
    const KEY = 'product_cart';

    public static function all()
    {
        return session()->get(self::KEY, []);
    }

    public static function add($item)
    {
        $cart = self::all();
        $found = false;

        foreach ($cart as &$cartItem) {
            if (
                $cartItem['product_id'] == $item['product_id'] &&
                $cartItem['date'] == $item['date']
            ) {
                $cartItem['quantity'] += $item['quantity'];
                $cartItem['total'] = $cartItem['quantity'] * $cartItem['price'];
                $found = true;
                break;
            }
        }

        if (!$found) {
            $cart[] = $item;
        }

        session()->put(self::KEY, $cart);
    }

    public static function clear()
    {
        session()->forget(self::KEY);
    }
}

This ensures:

  • Users can add multiple different products
  • If a product with the same date already exists → quantities merge

Step 4: Create Livewire Component – Product Booking Form

Create a product booking component using the following artisan command:

php artisan make:livewire BookProductForm

It will create 2 files for product booking,

  • Class File: app/Livewire/BookProductForm.php
  • Blade File: resources/views/livewire/book-product-form.blade.php

Livewire Component Logic

Add the below product booking logic code to the app/Livewire/BookProductForm.php file.

namespace App\Livewire;

use App\Models\Product;
use App\Services\CartService;
use Livewire\Component;

class BookProductForm extends Component
{
    public Product $product;
    public $date;
    public $quantity = 1;

    protected $rules = [
        'date' => 'required|date'
    ];

    public function incrementQty()
    {
        $this->quantity++;
    }

    public function decrementQty()
    {
        if ($this->quantity > 1) {
            $this->quantity--;
        }
    }

    public function bookNow()
    {
        $this->validate();

        CartService::add([
            'product_id' => $this->product->id,
            'name'       => $this->product->name,
            'price'      => $this->product->price,
            'date'       => $this->date,
            'quantity'   => $this->quantity,
            'total'      => $this->quantity * $this->product->price
        ]);

        $this->dispatch('cart-updated');

        $this->reset('date', 'quantity');

        session()->flash('success', 'Product added to cart!');
    }

    public function render()
    {
        return view('livewire.book-product-form');
    }
}

Blade View with Message

Add the following code to the resources/views/livewire/book-product-form.blade.php.

<div class="card p-4 shadow-sm">

    @if(session('success'))
        <div class="alert alert-success">{{ session('success') }}</div>
    @endif

    <h4 class="mb-3">Book: {{ $product->name }}</h4>

    <div class="mb-3">
        <label>Date <span class="text-danger">*</span></label>
        <input type="date" class="form-control" wire:model="date">
        @error('date') <small class="text-danger">{{ $message }}</small> @enderror
    </div>

    <div class="mb-3">
        <label>Quantity</label>
        <div class="input-group" style="width: 150px;">
            <button class="btn btn-outline-secondary" wire:click="decrementQty">-</button>
            <input type="text" class="form-control text-center" wire:model="quantity" readonly>
            <button class="btn btn-outline-secondary" wire:click="incrementQty">+</button>
        </div>
    </div>

    <button class="btn btn-primary w-100" wire:click="bookNow">
        Book Now (₹{{ number_format($product->price, 2) }})
    </button>
</div>

Step 5: Create Livewire Cart Sidebar Component

Cart booking form is ready, but on clicking add to cart button, product is added to the cart. To display this cart, create a cart sidebar livewire component using the below artisan command:

php artisan make:livewire CartSidebar

Component class and blade files will be created as follows,

  • Class File: app/Livewire/CartSidebar.php
  • Blade File: resources/views/livewire/cart-sidebar.blade.php

Livewire Component Logic

Cart sidebar should display all cart products from the cart service. Add the below code to app/Livewire/CartSidebar.php file,

namespace App\Livewire;

use App\Services\CartService;
use Livewire\Component;

class CartSidebar extends Component
{
    protected $listeners = ['cart-updated' => '$refresh'];

    public function render()
    {
        return view('livewire.cart-sidebar', [
            'cart' => CartService::all()
        ]);
    }
}

Blade view with Total Amount

The below code is for resources/views/livewire/cart-sidebar.blade.php file, to display all cart products and the total amount of the cart.

<div class="card p-3 shadow-sm" style="position: sticky; top: 10px;">

    <h5 class="mb-3">Your Cart</h5>

    @if(empty($cart))
        <p>No products in cart.</p>
    @else
        @foreach($cart as $item)
            <div class="border-bottom pb-2 mb-2">
                <strong>{{ $item['name'] }}</strong><br>
                Date: {{ $item['date'] }}<br>
                Qty: {{ $item['quantity'] }}<br>
                <span class="fw-bold">₹{{ $item['total'] }}</span>
            </div>
        @endforeach

        <div class="text-end fw-bold">
            Total: ₹{{ array_sum(array_column($cart, 'total')) }}
        </div>
    @endif
</div>

Step 6: Using Livewire Components

Finally, both of the components are ready. They are ready to be used anywhere. To test, add both these components to product details page as follows,

@extends('layouts.app')

@section('content')
<div class="container py-5">
    <div class="row">

        <div class="col-md-8">
            <h2>{{ $product->name }}</h2>
            <p>{{ $product->description }}</p>
            <p class="fw-bold">Price: ₹{{ number_format($product->price, 2) }}</p>

            <livewire:book-product-form :product="$product" />
        </div>

        <div class="col-md-4">
            <livewire:cart-sidebar />
        </div>

    </div>
</div>
@endsection

Conclusion

You now have a complete Laravel Livewire v3 product booking system with:

✔ Date-based booking
✔ Quantity controls
✔ Real-time sidebar cart
✔ Merging duplicate entries

Can a user add multiple products to the cart?

Yes. Users can add unlimited products, each with separate date and quantity options.

Does the system merge identical cart items?

Yes. If users select the same product with the same date again, quantity is merged.

Is Livewire v3 required?

Yes. This tutorial uses Livewire v3 components, events, and reactive structure.

Can I add checkout or payment later?

Absolutely! This system is designed to extend into a full checkout workflow with payment gateway.

Build a Dynamic FullCalendar Component in Laravel Livewire

Learn how to build a dynamic FullCalendar component using Laravel Livewire 3. Load events based on calendar view, update without page reloads, and open event pages on click. Includes complete code, SEO tips, FAQ schema, and featured image.

If you’re building appointment systems, booking apps, task planners, or admin dashboards in Laravel, integrating a dynamic FullCalendar with Livewire 3 is one of the most powerful UI improvements you can make.

In this guide, we will create a SEO-optimized, production-ready FullCalendar component that:

  • Displays events dynamically
  • Loads events based on current calendar view (month/week/day)
  • Fetches events when navigation buttons are clicked
  • Refreshes events without breaking Livewire
  • Opens a single event page on event click

This tutorial is perfect for Livewire developers who want to build modern, reactive calendar features in Laravel.


Why Use FullCalendar With Livewire 3?

FullCalendar is one of the most flexible JavaScript calendar libraries available today. When combined with Livewire 3’s reactive power, you get:

  • Zero page reloads
  • Fast real-time interactions
  • Server-driven event handling
  • Clean API for filtering, loading & clicking events
  • Reusable UI components

Step 1: Install FullCalendar

Add CDN links in your layout:

<link href="https://cdn.jsdelivr.net/npm/fullcalendar@6.1.9/index.global.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/fullcalendar@6.1.9/index.global.min.js"></script>

Step 2: Create the Livewire Calendar Component

Run the following artisan command to create a livewire component,

php artisan make:livewire calendar

It will create the following files,

  • app/Livewire/Calendar.php
  • resources/views/livewire/calendar.blade.php

Step 3: Livewire Component Logic (Calendar.php)

Copy this core logic to app/Livewire/Calendar.php file.

<?php

namespace App\Livewire;

use App\Models\Event;
use Livewire\Component;

class Calendar extends Component
{
    public $events = [];

    protected $listeners = [
        'fetchEvents' => 'loadEvents',
    ];

    public function mount()
    {
        $this->loadEvents(now()->startOfMonth(), now()->endOfMonth());
    }

    public function loadEvents($start, $end)
    {
        $this->events = Event::whereDate('start_date', '<=', $end)
            ->whereDate('end_date', '>=', $start)
            ->get()
            ->map(fn($e) => [
                'id'    => $e->id,
                'title' => $e->title,
                'start' => $e->start_date,
                'end'   => $e->end_date,
                'url'   => route('event.details', ['slug' => $e->slug])
            ])
            ->toArray();

        $this->dispatch('refreshCalendar', $this->events);
    }
    
    public function render()
    {
        return view('livewire.calendar');
    }
}

This ensures all events are always pushed correctly to the frontend.


Step 4: Blade View With Event Click Redirect

<div wire:ignore x-data="calendarComponent()" x-init="initCalendar()">
    <div id="calendar"></div>
</div>

<script>
    function calendarComponent() {
        return {
            calendar: null,

            initCalendar() {
                const calendarEl = document.getElementById('calendar');

                this.calendar = new FullCalendar.Calendar(calendarEl, {
                    initialView: 'dayGridMonth',
                    selectable: true,
                    events: @json($events),
                    headerToolbar: {
                        left: 'prev,next today',
                        center: 'title',
                        right: 'dayGridMonth,dayGridWeek,timeGridDay,listWeek'
                    },

                    datesSet: (info) => {
                        // Date range changed → fetch events
                        Livewire.dispatch('fetchEvents', {
                            start: info.startStr,
                            end: info.endStr
                        });
                    },

                    eventClick(info) {
                        info.jsEvent.preventDefault();
                        if (info.event.url) {
                            window.location.href = info.event.url;
                        }
                    },
                });

                this.calendar.render();

                // Updating events when Livewire refreshes
                Livewire.on('refreshCalendar', (events) => {
                    this.calendar.refetchEvents();
                });
            }
        }
    }
</script>

This creates a perfectly working FullCalendar with:

  • Navigational event loading
  • Correct date range handling
  • Click-to-redirect event pages
  • Safe event refresh

Step 5: Create SEO-Friendly Event URLs

Route::get('/events/{event}', [EventController::class, 'show'])->name('events.show');

Now every event opens its own page, improving SEO with schema-friendly URLs.


Benefits of This Implementation

  • Lightning-fast Livewire updates
  • Works with any event table structure
  • Perfect for admin dashboards, booking systems & CRMs
  • No page reloads
  • Mobile-friendly
  • Great for SEO (event URLs help Google index your content)

FAQ Section

1. Why are my events not appearing in FullCalendar?

Because FullCalendar requires start, end, and title fields in a strict structure.
The tutorial fixes this by mapping events manually.

2. Can I open a popup instead of redirecting on event click?

Yes. You can use Bootstrap, Alpine, Filament modal, or Livewire modal.
Just tell the preferred method.

3. Does this support drag & drop?

FullCalendar supports it.
Livewire can listen to eventDrop and update your event in DB.

4. How do I load events filtered by category or user?

Inside loadEvents(), simply add:

->where('category_id', $this->selectedCategory)

5. Does this support recurring events?

Yes — FullCalendar can expand recurring event rules during load.