How to set up Tinymce with Laravel !

A few days ago I have installed laravel in server and I was trying to make my own customized backend for the project. I was looking for editors which most of them are not easy to use and some of them were heavy for the backend. Most importantly I need to insert images in my articles, but it was not easy to integrate them. Later on, I came across Tinymce. But it was not easy to integrate into my backend either. I came across some difficulties while I was trying to insert images to my articles. I would like to share it with you guys. I would explain the problems from three different views. Let's go

Front end

You can find a lot of front end code examples. I even found some code on TinyMCE official website, which did not work for me. You guys still can use them, but I am not sure whether it would work for you. But I will share the code I have used for inserting images. 

The front end code I have used is given below

@section('editorlink')
  <script src="https://cdn.tiny.cloud/1/no-api-key/tinymce/5/tinymce.min.js" referrerpolicy="origin"></script>

<script>
        tinymce.init({
            selector: '#description',
            height: 500,
            setup: function (editor) {
                editor.on('init change', function () {
                    editor.save();
                });
            },
            plugins: [
                "advlist autolink lists link image charmap print preview anchor",
                "searchreplace visualblocks code fullscreen",
                "insertdatetime media table contextmenu paste media code imagetools"
            ],
            toolbar: "insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image | code",
            theme_advanced_buttons1: "code", 
            media_strict: false,
            image_dimensions: false,
            image_class_list: [
            {title: 'Responsive', value: 'img-responsive'}
            ],
            image_title: true,
            automatic_uploads: true,
            images_upload_url: '/upload',
            file_picker_types: 'image',
            file_picker_callback: function(cb, value, meta) {
                var input = document.createElement('input');
                input.setAttribute('type', 'file');
                input.setAttribute('accept', 'image/*');
                input.onchange = function() {
                    var file = this.files[0];

                    var reader = new FileReader();
                    reader.readAsDataURL(file);
                    reader.onload = function () {
                        var id = 'blobid' + (new Date()).getTime();
                        var blobCache =  tinymce.activeEditor.editorUpload.blobCache;
                        var base64 = reader.result.split(',')[1];
                        var blobInfo = blobCache.create(id, file, base64);
                        blobCache.add(blobInfo);
                        cb(blobInfo.blobUri(), { title: file.name });
                        console.log(blobInfo.blobUri());
                    };
                };
                input.click();
            }
        });
    </script>
@endsection
@section('content')
<div class="col-md-12 box">
  <form method="POST" action="/posts/{{$id}}/tasks" enctype="multipart/form-data">
   
    {{csrf_field()}}

      <div class="form-group row">
        <label  class="col-sm-2 col-form-label">Title</label>
        <div class="col-sm-10">
          <input type="text" class="form-control" name="title"  required>
        </div>
      </div>
      <div class="form-group row">
        <label  class="col-sm-2 col-form-label">Description</label>
        <div class="col-sm-10">
            <textarea id="description" rows="20" cols="100" type="text" class="form-control" name="description"   required></textarea>

          </div>
        </div>
      </div>


      <div class="form-group row">
        <div class="col-sm-10">
          <button type="submit" class="btn btn-primary">Add Post</button>
        </div>
      </div>
  </form>
</div>
@endsection

Let me explain few things that you need to keep in mind while you integrate this code to your front-end. When you call the init method of tinymce the selector must match the id of the text area. In my code it's

selector:'#description'

Another important part of the code is

images_upload_url='/upload'

This url is used for post request. Make sure it matches the route of your web config in web.php file. Your url name could be anything as long as it same your route name.

Back end 

Your back end code should have two parts, one is route and the other one is controller. 

In web.php file you should add code like this given below

Route::post('/upload', 'AdminPostsController@uploadImage');

As you can see the post method route matches the url of images_upload_url which is mentioned in the front end code.

And controller part

public function uploadImage(){

        $imgpath = request()->file('file')->store('uploads', 'public'); 
        return response()->json(['location' => "/storage/$imgpath"]);

}

The above method is called from the web.php route. The uploadImage() method's first line says that save the uploaded image in the "uploads" folder of the public folder so that the image could be access publicly from the browser and at the same time return the image url. So the first line means that upload the image in the "uploads" folder and return the image url.  By default, pulic folder is created under storage/app directory of your laravel project. The second line means that save the image in the storage folder and send the response as json to the front end. The directory structure is in the below image

Laravel storage for image upload

 

Also, remember that you should type in 'file' in request()->file('parameter') as it's parameter otherwise you might get internal error 500. If your first line of code in the uploadImage() method has error most likely you will get error 500. You need to check log files in this case. Apart from this I also had to mention ajax post route in VerifyCsrfToken.php class like below

<?php

namespace App\Http\Middleware;

use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;

class VerifyCsrfToken extends Middleware
{
    /**
     * Indicates whether the XSRF-TOKEN cookie should be set on the response.
     *
     * @var bool
     */
    protected $addHttpCookie = true;

    /**
     * The URIs that should be excluded from CSRF verification.
     *
     * @var array
     */
    protected $except = [ '/upload' ];
}

Server-side

If you don't see uploads folder in your storage directory then you need to run below command 

--> php artisan storage:link

In my case, I did not have the uploads folder so images were not uploaded, so I kept getting 404 error. After digging a lot, I found that I need manually create this folder by using the above command. 

If you follow the above the three steps you should be good to go.

At the same time you may run the below commands

-->php artisan cache:clear

-->php artisan config:clear

-->php artisan route:clear

if necessary.

If you liked it please forward the post and help others.