Интеграция редактора Editor.js в CMS сайта
Editor.js — блочный редактор с чистым JSON-выводом. Каждый параграф, заголовок, изображение — отдельный блок с типизированными данными. Это делает контент структурированным и переносимым между платформами.
Установка
npm install @editorjs/editorjs @editorjs/paragraph @editorjs/header @editorjs/image
npm install @editorjs/list @editorjs/quote @editorjs/code @editorjs/table
Инициализация
import EditorJS from '@editorjs/editorjs';
import Header from '@editorjs/header';
import Image from '@editorjs/image';
import List from '@editorjs/list';
const editor = new EditorJS({
holder: 'editor-container',
placeholder: 'Начните вводить контент...',
tools: {
header: {
class: Header,
config: { levels: [2, 3, 4], defaultLevel: 2 }
},
image: {
class: Image,
config: {
uploader: {
uploadByFile: async (file) => {
const formData = new FormData();
formData.append('image', file);
const response = await fetch('/api/media/upload', {
method: 'POST', body: formData
});
const data = await response.json();
return { success: 1, file: { url: data.url } };
}
}
}
},
list: { class: List, inlineToolbar: true },
quote: { class: Quote, inlineToolbar: true }
},
data: initialData // JSON из БД
});
// Сохранение
const savedData = await editor.save();
// savedData.blocks — массив блоков
Формат данных
{
"time": 1710500000000,
"blocks": [
{ "type": "header", "data": { "text": "Заголовок статьи", "level": 2 } },
{ "type": "paragraph", "data": { "text": "Текст абзаца <b>с форматированием</b>." } },
{ "type": "image", "data": { "file": { "url": "/uploads/photo.jpg" }, "caption": "Подпись" } },
{ "type": "list", "data": { "style": "ordered", "items": ["Первый", "Второй"] } }
]
}
Рендеринг JSON на стороне сервера
Для SSR или серверной генерации HTML из Editor.js JSON:
// PHP: конвертация Editor.js JSON → HTML
class EditorJsRenderer
{
public function render(array $data): string
{
return collect($data['blocks'])->map(fn($block) =>
match($block['type']) {
'header' => "<h{$block['data']['level']}>{$block['data']['text']}</h{$block['data']['level']}>",
'paragraph' => "<p>{$block['data']['text']}</p>",
'image' => "<figure><img src=\"{$block['data']['file']['url']}\" alt=\"{$block['data']['caption']}\"><figcaption>{$block['data']['caption']}</figcaption></figure>",
'list' => $this->renderList($block['data']),
'quote' => "<blockquote>{$block['data']['text']}<cite>{$block['data']['caption']}</cite></blockquote>",
default => ''
}
)->implode("\n");
}
}
Кастомный инструмент
class CalloutBlock {
static get toolbox() {
return { title: 'Callout', icon: '<svg>...</svg>' };
}
render() {
this.wrapper = document.createElement('div');
this.wrapper.className = 'callout-block';
this.wrapper.contentEditable = true;
return this.wrapper;
}
save(element) {
return { text: element.innerHTML };
}
}
Срок интеграции: 1–2 дня для базового редактора с загрузкой изображений и серверным рендерингом.







