Filter post_content before loading in Gutenberg editor

I found that there is no way to change the data which is coming to editor when it is loaded. But it’s possible to replace the data after that.

JS: script.js

wp.domReady(function () {
    const newData = window.myNewBlocksData;

    if (newData) {
        wp.data.dispatch('core/block-editor').resetBlocks(wp.blocks.parse(newData));
        console.log('replaced');
    }
}) 

PHP:

<?php

class MyBlocksManipulation
{
    public $prefix = 'my';

    public function __construct()
    {
        add_action('admin_enqueue_scripts', [$this, 'modifyData'], 999);
        add_action('save_post', [$this, 'markPostManipulationDone'], 999, 3);
    }

    public function newDataType()
    {
        $screen = get_current_screen();

        if (!(
            $screen !== null &&
            !empty($screen->is_block_editor) &&
            !empty($screen->base) &&
            $screen->base === 'post'
        )) {
            return;
        }

        $currentPost = get_post();
        $alreadyManipulated = get_post_meta($currentPost->ID, "{$this->prefix}_data_is_modified", true);

        if (!empty($alreadyManipulated)) {
            return;
        }

        $newData = wp_slash($this->modifyData());

        wp_add_inline_script('wp-editor', "var myNewBlocksData=`{$newData}`");

        wp_enqueue_script(
            'my-data-manipulation',
            'path/to/my/script.js',
            ['wp-editor'],
            false,
            true
        );
    }

    public function modifyData()
    {
        $currentPost = get_post();
        $content = $currentPost->post_content;

        return preg_replace_callback("<!-- wp:(.*) ({(.*)}) \/-->", function ($matches) {
            if (!empty($matches[2])) {
                $array = self::decode_block_attributes($matches[2]);


                // ...
                // Do something with this $array ...
                // ...


                $block = new WP_Block_Parser_Block($matches[1], $array, [], '', []);

                $serialized = serialize_block((array)$block);

                $serialized = trim($serialized, '<>');

                return $serialized;
            }

            return "<$matches[0]>";
        }, $content);
    }

    public static function is_json($item)
    {
        if (is_string($item)) {
            $json = json_decode($item, true);

            return is_array($json) && json_last_error() == JSON_ERROR_NONE;
        }

        return false;
    }

    public static function decode_block_attributes($item)
    {
        if (self::is_json($item) || is_array($item)) {
            $json = is_array($item) ? $item : json_decode($item, true);

            return $json;
        }

        return $item;
    }

    public function markPostManipulationDone($postId, $post, $update)
    {
        if (
            !$update ||
            $post->post_type === 'revision' ||
            !current_user_can('edit_post', $postId)
        ) {
            return $postId;
        }

        return update_post_meta($postId, "{$this->prefix}_data_is_modified", current_time('U'));
    }
}

new MyBlocksManipulation(); // Somwhere on top, before the theme or plugin content is rendered.

Leave a Comment