Date
3 min read

How to save markdown using an editor and render it using Laravel

Table of contents:

Recommended packages to implement:

Markdown editor:

The Blade UI Kit package has a great out-of-the-box editor. The editor can optionally accept some parameters that can affect the styling and functionality of the editor. One of the editor’s features includes image uploads, this can be done using Spatie’s Media Library package. In this example, we will be associating images to the posts.

The editor is presented as a Blade component as per the below. We can then pass through the editor’s options using a ‘Post’ model. Just to note, Spatie’s package requires the model to preexist within the database, hence the conditionally checking.

{{-- Blade --}}
<x-easy-mde name="content" :options="$post->getEditorOptions()">
  {!! $post->content !!}
</x-easy-mde>
class Post extends Model
{
    // ...

    /**
     * @see https://github.com/Ionaru/easy-markdown-editor
     */
    public function getEditorOptions(): array
    {
        $options = [
            'minHeight' => '700px',
            'tabSize' => 4,
        ];

        if ($this->exists) {
            $options = array_merge($options, [
                'uploadImage' => true,
                'imageUploadEndpoint' => route('admin.posts.images.store', $this),
                'imageCSRFToken' => csrf_token(),
                'imageCSRFName' => '_token',
                'imagePathAbsolute' => false,
            ]);
        }

        return $options;
    }
}

Below is an example of a dedicated Controller that handles file uploads from the editor and the associating with a given post.

public function store(PostImageRequest $request, Post $post)
{
	$request->validate([
		'image' => 'required|file',
	]);

	$image = $post->addMediaFromRequest('image')
		->toMediaCollection('post_content_images');

	return response()->json([
		'data' => [
			'filePath' => $image->getPathRelativeToRoot(),
		],
	]);
}

Lastly, we can have another separate Controller for handling the saving of the post’s content. Also, it’s important to remove any unused images for the post to save on storage space.

$post->update($request->safe()->only([
	'content',
]));

$postContent = $post->content;

foreach ($post->getMedia('post_content_images') as $image) {
	if (! Str::contains($postContent, $image->getPathRelativeToRoot())) {
		$image->delete();
	}
}

Markdown presenter:

Now you’ll want to convert the markdown content. You can use Spatie’s markdown package to achieve this i.e.

{{-- Blade --}}
<x-markdown>{!! $post->content !!}</x-markdown>

The only annoyance here is that this component’s name conflicts with that of the Blade UI Kit package. A simple way around this is to just create a dedicated Blade component with a unique, non-conflicting name that just extends Spatie’s.

<?php

namespace App\View\Components;

use Spatie\LaravelMarkdown\MarkdownBladeComponent;

class Markdown extends MarkdownBladeComponent
{
    // ...
}

This could then be registered within a Service Provider, like the following:

use App\View\Components\Markdown;

/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot()
{
	Blade::component('markdown-renderer', Markdown::class);
}

You may want to make use of Tailwind’s typography library to use the ‘prose’ class. This will nicely present and format the HTML for you.

{{-- Blade --}}
<x-markdown-renderer class="lg:flex-grow [max-width:unset] prose prose-img:w-full prose-img:rounded-md prose:pre:bg-secondary mt-12" theme="one-dark-pro">{!! $post->content !!}</x-markdown-renderer>

Lastly, be sure to reminder the following with regards to the markdown package:

  1. Make node executable on the server i.e. sudo ln -s "$(which node)" /usr/local/bin
  2. Ensure node_modules are present for the project on the server

You might also like...

  • Read article

    Generating and Enforcing UUIDs in Laravel for Immutable Model IDs

    Ensure models always have a UUID set.

  • Read article

    Exporting large amounts of data in Laravel

    An opinionated approach on how best to handle exporting large amounts of data in Laravel using commands and queues.

  • Read article

    Simple breadcrumbs in Laravel

    Breadcrumbs are a crucial navigation element in web applications, providing users with a clear path to follow within your site's hierarchy. By the end, you'll have an easy-to-use breadcrumb system that enhances your site's user experience.

Let's work together 🤝

Line
Christopher Kelker

Chriscreates