Skip to main content

Implementing simple file uploads in TinyMCE editor

It seems to be a common misconception that in order to have file uploads in the TinyMCE editor, you need to install or pay for a plugin. But TinyMCE has file uploads baked right in! All that you need to do is implement a handler into your application to enable it.

There are different ways to implement file uploads in TinyMCE, the docs have examples that can be used with native PHP and jQuery, but here I will run through the steps of adding the filehandler to a default Laravel installation.

First, is to make sure TinyMCE is loaded in your html. You can self-host the editor by downloading or including it in your dependencies with npm. For simplicity I will just load it from the cdn, don't forget to add your API key.

<script src="https://cdn.tiny.cloud/1/API_KEY_HERE/tinymce/5/tinymce.min.js" referrerpolicy="origin"></script>

Next, you need to initialise TinyMCE in your JS file, ensure that the relevant plugins and toolbar options are enabled and use Axios to handle the file upload to the server. Here is the most basic example that I have added to the default app.js file to handle images:

tinymce.init({
    selector: 'textarea',
    plugins: [
        "image"
    ],
    toolbar1: "image",
    file_picker_types: 'image',
    images_upload_handler: function (blobInfo, success, failure) {
        let data = new FormData();
        data.append('file', blobInfo.blob(), blobInfo.filename());
        axios.post('/file-upload', data)
            .then(function (res) {
                success(res.data.location);
            })
            .catch(function (err) {
                failure('HTTP Error: ' + err.message);
            });
    }

});

Here we have enabled the image plugin and added it to the toolbar. Next we have added a file upload handler that takes the file and posts it to the server url /file-upload using Axios.

Note: You will need to compile your JS using npm, the easiest way is to run npm run dev using the default Laravel Mix setup.

Now we need to add our route to the routes/web.php file. You will most likely want to only allow this functionality to authenticated users to keep things secure, so I have added the auth middleware to the route.

Route::post('/file-upload', 'FileController@upload')->middleware('auth');

Next we need to create our FileController that will handle the file upload.

php artisan make:controller FileController

And finally...

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Storage;

class FileController extends Controller
{

    /**
    * Handle file upload and return location.
    *
    * @param  Illuminate\Http\Request  $request
    * @return \Illuminate\Http\Response
    */
    public function upload(Request $request)
    {
        $validatedData = $request->validate([
            'file' => 'required|file',
        ]);
    
        $path = $request->file('file')->store('uploads', 'public');
        return ['location' => Storage::url($path)];
    }    
    
}

Inside our FileController we have created the upload method, validated the request to ensure it is a file, stored it in our public storage in a folder called uploads and returned the fully qualified url for TinyMCE to use in the editor. Now you should have an upload option when clicking the image button in TinyMCE. It really is that easy!