How to integrate tinymce editor in laravel 11(with livewire)

First, we need to add third party script to our blade file. We can use @asset directive for injecting third party script.

@assets
<script src="{{ asset('build/public/js/tinymce/tinymce/tinymce.min.js') }}" referrerpolicy="origin"></script>
<script>
tinymce.init({
selector: '#details', // Replace this CSS selector to match the placeholder element for TinyMCE
plugins: 'preview importcss searchreplace autolink autosave directionality anchor insertdatetime advlist lists quickbars emoticons',
toolbar: "blocks fontfamily fontsize | bold italic underline strikethrough | align numlist bullist | forecolor backcolor emoticons",
promotion: false,
menubar: '',
height: 500,
branding: false,
statusbar: false,
setup: function(editor) {
editor.on('init change', function() {
editor.save();
});
editor.on('change', function(e) {
@this.set('details', editor.getContent());
});
},
});
</script>
@endassets

After adding this, tinymce edit shows up. Because I am using Livewire for the front part, I had to add wire:ignore to the parent element of #details. Also whenever the content of the editor changes, it will update the $details property with updated contents.

I wanted to save this content to the database(MySQL). To handle every images in the content, I needed to use dom parser.

public function save()
{
// save this product to retrieve id of the product.
$newProrduct = new Product();
$newProrduct->user_id = auth()->user()->id;
... // set all the property for the new product.
$newProrduct->save();
 
// partse the content from the Tinymce editor
$dom = new \DomDocument();
$dom->loadHtml($this->details, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
 
// get all images
$imageFile = $dom->getElementsByTagName('img');
 
foreach ($imageFile as $item => $image) {
$data = $image->getAttribute('src');
list($type, $data) = explode(';', $data);
list(, $data) = explode(',', $data);
$imageData = base64_decode($data);
$image_name = time() . $item . '.png';
 
// create a folder name with its id and save all the images in it.
// I am using r2 storage.
Storage::disk('r2')->put("products/{$newProrduct->id}/" . $image_name, $imageData);
 
$image->removeAttribute('src');
$image->setAttribute('src', env('CLOUDFLARE_R2_URL') . "products/{$newProrduct->id}/" . $image_name);
}
 
// save adjusted contents to the database
$newProrduct->details = $dom->saveHTML();
$newProrduct->save();
 
return redirect()->intended(route('products'));
}

The logic is pretty simple and straight forward. It might be good idea to create a method for handling images from the contents from the tinymce editor.