CKEditor is a widely use WYSIWYG (What You See Is What You Get) editor. It provides all the basic features that are required for formatting.
The editor works perfectly but you need to write extra code for file upload through the editor.
In this tutorial, I show how you can add CKeditor 5 to an HTML element and save it to the MySQL database in Laravel 9.

Contents
- Database Configuration
- Table structure
- Model
- Controller
- Route
- Download CKEditor 5
- View
- Output
- Conclusion
1. Database Configuration
Open .env file.
Specify the host, database name, username, and password.
DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=tutorial DB_USERNAME=root DB_PASSWORD=
2. Table structure
- Create a new table
messagesusing migration.
php artisan make:migration create_messages_table
- Now, navigate to
database/migrations/folder from the project root. - Find a PHP file that ends with
create_messages_tableand open it. - Define the table structure in the
up()method.
public function up()
{
Schema::create('messages', function (Blueprint $table) {
$table->id();
$table->string('subject');
$table->text('message');
$table->timestamps();
});
}
- Run the migration –
php artisan migrate
3. Model
- Create
MessagesModel –
php artisan make:model Messages
- Open
app/Models/Messages.phpfile. - Specify mass assignable Model attributes – subject, and message using the
$fillableproperty.
Completed Code
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Messages extends Model
{
use HasFactory;
protected $fillable = [
'subject','message'
];
}
4. Controller
- Create
PagesControllercontroller –
php artisan make:controller PagesController
- Import
Validator,Session, andMessagesmodel.
Create 3 methods –
- index() – Load
indexview. - uploadFile() – Using this method upload the selected file from the CKEditor. Access file using
uploadname.
Validate the file. If not validated then assign 0 to $data['uploaded'] and error message to $data['error']['message'].
If validated successfully then upload the file to uploads folder.
After upload assign $filename to $data['fileName'], 1 to $data['uploaded'], and $filepath to $data['url'].
- submitform() – Using this method handle form submit.
Validate the submitted values. If not validated then return to the page with error messages otherwise insert a new record in the messages table, and specify the success message in SESSION flash.
Redirect page to /.
Completed Code
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Session;
use App\Models\Messages;
class PagesController extends Controller
{
public function index(){
return view('index');
}
// Upload CkEditor file
public function uploadFile(Request $request){
$data = array();
$validator = Validator::make($request->all(), [
'upload' => 'required|mimes:png,jpg,jpeg|max:2048'
]);
if ($validator->fails()) {
$data['uploaded'] = 0;
$data['error']['message'] = $validator->errors()->first('upload');// Error response
}else{
if($request->file('upload')) {
$file = $request->file('upload');
$filename = time().'_'.$file->getClientOriginalName();
// File upload location
$location = 'uploads';
// Upload file
$file->move($location,$filename);
// File path
$filepath = url('uploads/'.$filename);
// Response
$data['fileName'] = $filename;
$data['uploaded'] = 1;
$data['url'] = $filepath;
}else{
// Response
$data['uploaded'] = 0;
$data['error']['message'] = 'File not uploaded.';
}
}
return response()->json($data);
}
// Submit form
public function submitform(Request $request){
$validator = Validator::make($request->all(), [
'subject' => 'required',
'message' => 'required',
]);
if ($validator->fails()) {
return redirect()->Back()->withInput()->withErrors($validator);
}else{
// Insert record
Messages::create([
'subject' => $request->subject,
'message' => $request->message
]);
Session::flash('message','Form submit Successfully.');
}
return redirect('/');
}
}
5. Route
- Open
routes/web.phpfile. - Define 3 routes –
- / – Load
indexview. - /uploadFile – This is use to upload CKEditor selected file.
- /submitform – Handle form submit.
- / – Load
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PagesController;
Route::get('/', [PagesController::class, 'index']);
Route::post('/submitform',[PagesController::class,'submitform'])->name('submitform');
Route::post('/uploadFile',[PagesController::class,'uploadFile'])->name('uploadFile');
6. Download CKEditor 5
- Download CKEditor 5 library from here or you can use CDN –
<!-- ckeditor5 JS --> <script src="https://cdn.ckeditor.com/ckeditor5/35.4.0/classic/ckeditor.js"></script>
7. View
Create index.blade.php file in resources/views/ folder.
HTML
Create a <form >. Set its action to {{ route('submitform') }}.
Here, create a textbox, textarea element, and a submit button. Define CKEditor on textarea.
Script
Initialize CKEditor on .editor class. Using ckfinder to set upload file URL.
Set uploadUrl to "{{route('uploadFile').'?_token='.csrf_token()}}". Here, pass the CSRF token with the URL.
Completed Code
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>Add CKEditor 5 and save it to MySQL database in Laravel</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" >
<style type="text/css">
.ck-editor__editable {
min-height: 250px;
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-8 mt-5" style="margin: 0 auto;">
<!-- Alert message (start) -->
@if(Session::has('message'))
<div class="alert alert-success">
{{ Session::get('message') }}
</div>
@endif
<!-- Alert message (end) -->
<form method="post" action="{{ route('submitform') }}">
@csrf
<div class="form-group mb-4">
<label class="control-label col-sm-2" for="subject">Subject:</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="name" placeholder="Enter Subject" name="subject" value="{{ old('subject') }}">
</div>
<!-- Error -->
@if($errors->has('subject'))
<div class='text-danger mt-2'>
* {{ $errors->first('subject') }}
</div>
@endif
</div>
<div class="form-group mb-4">
<label class="control-label col-sm-2" for="message">Message:</label>
<div class="col-sm-10">
<textarea class="form-control editor" name="message"></textarea>
</div>
<!-- Error -->
@if($errors->has('message'))
<div class='text-danger mt-2'>
* {{ $errors->first('message') }}
</div>
@endif
</div>
<div class="form-group ">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-info">Submit</button>
</div>
</div>
</form>
</div>
</div>
</div>
<!-- Script -->
<script src="https://cdn.ckeditor.com/ckeditor5/35.4.0/classic/ckeditor.js"></script>
<script type="text/javascript">
ClassicEditor
.create( document.querySelector( '.editor' ),{
ckfinder: {
uploadUrl: "{{route('uploadFile').'?_token='.csrf_token()}}",
}
} )
.then( editor => {
console.log( editor );
} )
.catch( error => {
console.error( error );
} );
</script>
</body>
</html>
8. Output
9. Conclusion
CKEditor element data is directly accessible after submission on the server side.
If you want to show stored CKEditor data in MySQL database then read and store it in CKEditor textarea element.
If you found this tutorial helpful then don't forget to share.