How to integrate GrapesJS into WordPress (complete guide 2026)

Add a GrapesJS drag-and-drop editor to WordPress: enqueue it on an admin page, save content through the REST API with a nonce, and render it with a shortcode.

DevFuture Development
DevFuture Development
Apr 23, 20262 months ago
9 min read1 views

When to use GrapesJS with WordPress

GrapesJS is a standalone, MIT-licensed editor — not a Gutenberg block. Embed it in WordPress when you need a fully custom, framework-agnostic drag-and-drop editor with your own storage and export pipeline. This guide builds a small plugin: an admin page that hosts the editor, a REST endpoint that saves content with a nonce, and a shortcode that renders it on the front end.

1. Create the plugin and enqueue GrapesJS

In wp-content/plugins/gjs-editor/gjs-editor.php, register an admin page and enqueue GrapesJS only on that screen. Pass a REST nonce to the script.

<?php
/* Plugin Name: GJS Editor */

add_action('admin_menu', function () {
    add_menu_page('GrapesJS', 'GrapesJS', 'edit_pages', 'gjs-editor', function () {
        echo '<div id="gjs"><h1>Edit me</h1></div>';
    });
});

add_action('admin_enqueue_scripts', function ($hook) {
    if ($hook !== 'toplevel_page_gjs-editor') {
        return;
    }
    wp_enqueue_style('grapesjs', 'https://unpkg.com/grapesjs/dist/css/grapes.min.css');
    wp_enqueue_script('grapesjs', 'https://unpkg.com/grapesjs', [], null, true);
    wp_enqueue_script('gjs-init', plugins_url('editor.js', __FILE__), ['grapesjs'], null, true);
    wp_localize_script('gjs-init', 'GJS', [
        'root'  => esc_url_raw(rest_url('gjs/v1/page')),
        'nonce' => wp_create_nonce('wp_rest'),
    ]);
});

2. Initialise GrapesJS with remote storage

In editor.js, point the Storage Manager at the REST route and send the nonce as the X-WP-Nonce header.

const editor = grapesjs.init({
  container: '#gjs',
  height: '100vh',
  fromElement: true,
  storageManager: {
    type: 'remote',
    stepsBeforeSave: 3,
    options: {
      remote: {
        urlStore: GJS.root,
        urlLoad: GJS.root,
        headers: { 'X-WP-Nonce': GJS.nonce },
      },
    },
  },
});

3. Register the REST endpoint

Store the project (and rendered html/css) with update_option. A custom post type works too if you need many pages.

add_action('rest_api_init', function () {
    register_rest_route('gjs/v1', '/page', [
        [
            'methods'             => 'GET',
            'permission_callback' => '__return_true',
            'callback'            => function () {
                return get_option('gjs_project', []);
            },
        ],
        [
            'methods'             => 'POST',
            'permission_callback' => function () {
                return current_user_can('edit_pages');
            },
            'callback'            => function (WP_REST_Request $req) {
                $data = $req->get_json_params();
                update_option('gjs_project', $data);
                update_option('gjs_html', $data['gjs-html'] ?? '');
                update_option('gjs_css', $data['gjs-css'] ?? '');
                return ['status' => 'ok'];
            },
        ],
    ]);
});

The X-WP-Nonce header lets WordPress authenticate the logged-in user, and permission_callback enforces the capability check.

4. Render on the front end with a shortcode

add_shortcode('gjs_page', function () {
    $css  = get_option('gjs_css', '');
    $html = get_option('gjs_html', '');
    return '<style>' . $css . '</style>' . $html;
});

Drop [gjs_page] into any post or page. Sanitise stored markup on output if non-admins can edit it.

Security & performance tips

Abstract data and security visualization
Enqueue the editor only where needed and guard the REST route.

Keep the integration lean and safe. Enqueue GrapesJS only on your editor screen (the admin_enqueue_scripts hook check), never site-wide, so the front end stays fast. Lock the REST save route with a permission_callback that calls current_user_can('edit_pages') and always send the X-WP-Nonce header — nonces expire (~24h), so refresh or re-issue the nonce for long sessions. Render shortcode output through wp_kses_post() rather than echoing it raw. For many pages, store each in a custom post type instead of options so revisions and capabilities come for free.

Prerequisites

You'll need WordPress 6+ and PHP 7.4+. This guide builds a small plugin, so basic familiarity with the plugin API (hooks, enqueueing scripts, the REST API, nonces, and capabilities) is enough. No build step is required — GrapesJS loads from a CDN or a bundled asset.

Add custom blocks to the editor

Register draggable blocks with the Block Manager after grapesjs.init:

editor.BlockManager.add('hero', {
  label: 'Hero section',
  category: 'Sections',
  content: '<section class="hero"><h1>Headline</h1><p>Copy</p></section>',
});

Pull ready-made block libraries and presets from GJS.Market for a richer set.

Store pages in a custom post type

Options work for a single page, but a custom post type gives you many pages plus revisions and capabilities for free. Register it and store the project in post meta, then read it back in the REST callbacks shown earlier. Keep the project, rendered HTML, and CSS together so a page re-opens exactly as saved.

Performance tips

Enqueue GrapesJS only on your editor screen (the admin_enqueue_scripts hook check), never site-wide, so the front end stays fast. Cache the shortcode output and bust it on save. Defer the editor script so it never blocks the admin UI.

Security considerations

Lock the REST save route with a permission_callback that calls current_user_can('edit_pages') and always send the X-WP-Nonce header — nonces expire (~24h), so refresh or re-issue them for long sessions. Render front-end output through wp_kses_post() rather than echoing raw markup.

Troubleshooting common errors

403 (rest_cookie_invalid_nonce) means the nonce is missing or expired. An unstyled canvas means the stylesheet wasn't enqueued. A blank editor means the container element wasn't on the admin page. If saves silently fail, confirm the capability check passes for the current user.

When to use GrapesJS with WordPress

GrapesJS suits a fully custom, framework-agnostic visual editor embedded in your own admin or product — when you want your own storage and HTML output rather than extending Gutenberg. If you only need to edit content inside WordPress with its block model, Gutenberg is the native choice; for a self-owned, embeddable page builder, GrapesJS is the stronger fit.

Next steps

Add blocks and plugins to match your theme. See the related GrapesJS + Laravel guide, compare editors on GrapesJS vs Builder.io, browse the GrapesJS marketplace, or start from the GJS.Market home page.

FAQ

How do I save GrapesJS content in WordPress?

Register a REST route, send the request with the X-WP-Nonce header, and store the project/html/css with update_option (or a custom post type).

Can GrapesJS replace the WordPress block editor?

GrapesJS is a standalone editor you embed yourself, not a Gutenberg block. Use it when you need a fully custom, framework-agnostic editor with your own storage and export rather than extending Gutenberg.

How do I authenticate the save request?

Pass a nonce from wp_create_nonce('wp_rest') via wp_localize_script, then send it as the X-WP-Nonce header so the REST permission_callback succeeds.

More tags:
Published Apr 23, 2026
Updated Jun 27, 2026
🔌 GJS.Market

Looking for GrapesJS plugins?

Over 100 curated plugins, presets, and templates — hand-picked for quality and maintained by the community.

Share this postTwitterFacebookLinkedIn
Published via
DevFuture Development
DevFuture Development
Visit shop →

More from DevFuture Development

Discover other insightful posts and stay updated with the latest content.

View all posts

Premium plugins from DevFuture Development

Hand-picked paid additions crafted by this creator.

Visit shop →