Table of contents
In my previous posts, I shared how to install TinyMCE with advanced configurations just search it with my previous blogs for you to learn. In this post, I will share how to integrate or implement TinyMCE Editor in Laravel 8. Adding a WYSIWYG editor in your Laravel application to your content management will be easier to format HTML view and display on your web page.
Â
Â
Now let's do the basics in this example I will share creating, viewing, and updating content using TinyMCE. We know that TinyMCE is one of the best Free WYSIWYGÂ powerful editors that many applications using TinyMCE.
Â
Okay, let's continue. I assume that you installed already your Laravel.
Â
Step 1: Table Setup
Let's create a posts table migration. Here is the example below:
Â
Run the below command first to create a migration:
php artisan make:migration create_posts_table
Â
Then add the following code inside up() method in your created migration.
Â
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id');
$table->string('title', 70);
$table->string('description', 320);
$table->text('body');
$table->timestamps();
$table->foreign('user_id')
->references('id')
->on('users')
->onDelete('cascade');
});
Â
As you can see I already added the user_id as an author for the post. So it's up to you if you want to implement it.
Â
Next, run the following command:
php artisan migrate
Â
Step 2: Setup Routes
Next, we will set up our posts routes. Add the following code to your routes file.
/**
* Posts Routes
*/
Route::group(['prefix' => 'posts'], function() {
Route::get('/', 'PostsController@index')->name('posts.index');
Route::get('/create', 'PostsController@create')->name('posts.create');
Route::post('/create', 'PostsController@store')->name('posts.store');
Route::get('/{post}/show', 'PostsController@show')->name('posts.show');
Route::get('/{post}/edit', 'PostsController@edit')->name('posts.edit');
Route::patch('/{post}/update', 'PostsController@update')->name('posts.update');
Route::delete('/{post}/delete', 'PostsController@destroy')->name('posts.destroy');
});
Â
Step 3: Download And Install TinyMCE Editor To Laravel Application
Now, let's download our TinyMCE Editor and install it to our Laravel application.
Â
First: Visit TinyMCE here.
Â
Then select then click "Download Self-Hosted" then click "Prod" the latest version of TinyMCE.
Â
Second: Once downloaded. Extract the zip file then rename the folder from tinymce_{version} to TinyMCE and copy it to your "public/assets" folder if assets are not yet existing then create the folder.
Â
Once done you will see js folder inside tinymce folder.
Â
To install Laravel TinyMCE just put the following script to your Laravel blade <head> tag.
<script src="{!! url('assets/tinymce/js/tinymce.min.js') !!}"></script>
Â
Check our previous blog about basic installation of TinyMCE.
Â
Step 4: Create Blade Files for our Laravel TinyMCE
Below are the files with blade code examples:
Â
app-master.blade.php
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors">
<meta name="generator" content="Hugo 0.87.0">
<title>Fixed top navbar example · Bootstrap v5.1</title>
<!-- Bootstrap core CSS -->
<link href="{!! url('assets/bootstrap/css/bootstrap.min.css') !!}" rel="stylesheet">
<script src="{!! url('assets/tinymce/js/tinymce.min.js') !!}"></script>
<style>
.bd-placeholder-img {
font-size: 1.125rem;
text-anchor: middle;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
@media (min-width: 768px) {
.bd-placeholder-img-lg {
font-size: 3.5rem;
}
}
.float-right {
float: right;
}
</style>
<!-- Custom styles for this template -->
<link href="{!! url('assets/css/app.css') !!}" rel="stylesheet">
</head>
<body>
@include('layouts.partials.navbar')
<main class="container mt-5">
@yield('content')
</main>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="{!! url('assets/bootstrap/js/bootstrap.bundle.min.js') !!}"></script>
@section("scripts")
@show
</body>
</html>
Â
index.blade.php
@extends('layouts.app-master')
@section('content')
<h1 class="mb-3">How To Integrate TinyMCE Editor in Laravel 8?</h1>
<div class="bg-light p-4 rounded">
<h2>Posts</h2>
<div class="lead">
Manage your posts here.
<a href="{{ route('posts.create') }}" class="btn btn-primary btn-sm float-right">Add post</a>
</div>
<div class="mt-2">
@include('layouts.partials.messages')
</div>
<table class="table table-bordered">
<tr>
<th width="1%">No</th>
<th>Name</th>
<th width="3%" colspan="3">Action</th>
</tr>
@foreach ($posts as $key => $post)
<tr>
<td>{{ $post->id }}</td>
<td>{{ $post->title }}</td>
<td>
<a class="btn btn-info btn-sm" href="{{ route('posts.show', $post->id) }}">Show</a>
</td>
<td>
<a class="btn btn-primary btn-sm" href="{{ route('posts.edit', $post->id) }}">Edit</a>
</td>
<td>
{!! Form::open(['method' => 'DELETE','route' => ['posts.destroy', $post->id],'style'=>'display:inline']) !!}
{!! Form::submit('Delete', ['class' => 'btn btn-danger btn-sm']) !!}
{!! Form::close() !!}
</td>
</tr>
@endforeach
</table>
<div class="d-flex">
{!! $posts->links() !!}
</div>
</div>
@endsection
Â
Â
create.blade.php
@extends('layouts.app-master')
@section('content')
<div class="bg-light p-4 rounded">
<h2>Add new post</h2>
<div class="lead">
Add new post.
</div>
<div class="container mt-4">
<form method="POST" id="save-content-form" data-action="{{ route('posts.store') }}">
@csrf
<div class="mb-3">
<label for="title" class="form-label">Title</label>
<input value="{{ old('title') }}"
type="text"
class="form-control"
name="title"
placeholder="Title" required>
@if ($errors->has('title'))
<span class="text-danger text-left">{{ $errors->first('title') }}</span>
@endif
</div>
<div class="mb-3">
<label for="description" class="form-label">Description</label>
<input value="{{ old('description') }}"
type="text"
class="form-control"
name="description"
placeholder="Description" required>
@if ($errors->has('description'))
<span class="text-danger text-left">{{ $errors->first('description') }}</span>
@endif
</div>
<div class="mb-3">
<label for="body" class="form-label">Body</label>
<textarea class="form-control"
id="tinymce">{{ old('body') }}</textarea>
@if ($errors->has('body'))
<span class="text-danger text-left">{{ $errors->first('body') }}</span>
@endif
</div>
<button type="submit" class="btn btn-primary">Save changes</button>
<a href="{{ route('posts.index') }}" class="btn btn-default">Back</a>
</form>
</div>
</div>
@endsection
@section('scripts')
<script type="text/javascript">
tinymce.init({
selector: 'textarea#tinymce',
height: 600
});
$(document).ready(function() {
var formId = '#save-content-form';
$(formId).on('submit', function(e) {
e.preventDefault();
var data = $(formId).serializeArray();
data.push({name: 'body', value: tinyMCE.get('tinymce').getContent()});
$.ajax({
type: 'POST',
url: $(formId).attr('data-action'),
data: data,
success: function (response, textStatus, xhr) {
window.location=response.redirectTo;
},
complete: function (xhr) {
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
var response = XMLHttpRequest;
}
});
});
});
</script>
@endsection
Â
show.blade.php
@extends('layouts.app-master')
@section('content')
<div class="bg-light p-4 rounded">
<h2>Show post</h2>
<div class="lead">
</div>
<div class="container mt-4">
<div>
Title: {{ $post->title }}
</div>
<div>
Description: {{ $post->description }}
</div>
<div>
Body: {!! $post->body !!}
</div>
</div>
</div>
<div class="mt-4">
<a href="{{ route('posts.edit', $post->id) }}" class="btn btn-info">Edit</a>
<a href="{{ route('posts.index') }}" class="btn btn-default">Back</a>
</div>
@endsection
Â
edit.blade.php
@extends('layouts.app-master')
@section('content')
<div class="bg-light p-4 rounded">
<h2>Update post</h2>
<div class="lead">
Edit post.
</div>
<div class="container mt-4">
<form method="POST" id="update-content-form" data-action="{{ route('posts.update', $post->id) }}">
@method('patch')
@csrf
<div class="mb-3">
<label for="title" class="form-label">Title</label>
<input value="{{ $post->title }}"
type="text"
class="form-control"
name="title"
placeholder="Title" required>
@if ($errors->has('title'))
<span class="text-danger text-left">{{ $errors->first('title') }}</span>
@endif
</div>
<div class="mb-3">
<label for="description" class="form-label">Description</label>
<input value="{{ $post->description }}"
type="text"
class="form-control"
name="description"
placeholder="Description" required>
@if ($errors->has('description'))
<span class="text-danger text-left">{{ $errors->first('description') }}</span>
@endif
</div>
<div class="mb-3">
<label for="body" class="form-label">Body</label>
<textarea
type="text"
class="form-control"
id="tinymce" required>{{ $post->body }}</textarea>
@if ($errors->has('body'))
<span class="text-danger text-left">{{ $errors->first('body') }}</span>
@endif
</div>
<button type="submit" class="btn btn-primary">Save changes</button>
<a href="{{ route('posts.index') }}" class="btn btn-default">Back</a>
</form>
</div>
</div>
@endsection
@section('scripts')
<script type="text/javascript">
tinymce.init({
selector: 'textarea#tinymce',
height: 600
});
$(document).ready(function() {
var formId = '#update-content-form';
$(formId).on('submit', function(e) {
e.preventDefault();
var data = $(formId).serializeArray();
data.push({name: 'body', value: tinyMCE.get('tinymce').getContent()});
$.ajax({
type: 'POST',
url: $(formId).attr('data-action'),
data: data,
success: function (response, textStatus, xhr) {
window.location=response.redirectTo;
},
complete: function (xhr) {
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
var response = XMLHttpRequest;
}
});
});
});
</script>
@endsection
Â
Step 5: Setup Controller
Now let's set up our controller. See below the complete code:
<?php
namespace App\Http\Controllers;
use App\Models\Post;
use Illuminate\Http\Request;
class PostsController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$posts = Post::latest()->paginate(10);
return view('posts.index', compact('posts'));
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
return view('posts.create');
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
Post::create(array_merge($request->only('title', 'description', 'body'),[
'user_id' => auth()->id()
]));
return response()->json(['redirectTo' => '/posts']);
}
/**
* Display the specified resource.
*
* @param \App\Models\Post $post
* @return \Illuminate\Http\Response
*/
public function show(Post $post)
{
return view('posts.show', [
'post' => $post
]);
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\Post $post
* @return \Illuminate\Http\Response
*/
public function edit(Post $post)
{
return view('posts.edit', [
'post' => $post
]);
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\Post $post
* @return \Illuminate\Http\Response
*/
public function update(Request $request, Post $post)
{
$post->update($request->only('title', 'description', 'body'));
return response()->json(['redirectTo' => '/posts']);
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\Post $post
* @return \Illuminate\Http\Response
*/
public function destroy(Post $post)
{
$post->delete();
return redirect()->route('posts.index')
->withSuccess(__('Post deleted successfully.'));
}
}
Â
Step 6: Setup Model
See below the complete code of our Post Model.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
use HasFactory;
protected $table = 'posts';
protected $fillable = [
'user_id',
'title',
'description',
'body'
];
}
Â
That's it I hope it helps. Now you have an idea already on how to integrate TinyMCE Editor in Laravel 8.
Â
Â
Download and test it in your local.
Read next