wordpressfiltereditoraction

Filter content in WordPress classic and block editor to load content from custom field


This one has got me stumped.

I am offloading my wp_posts > post_content data to a custom field called post_content. See class at end of question to see how I am doing this.

And I am trying to filter the content loaded into my classic or block editor, so the content is actually loaded from my custom field called post_content, rather than loaded from the default wp_posts table.

I've tried these 3 filters and actions (not at the same time and no luck)...

add_action('edit_form_after_title', [ $this, 'load_custom_post_content_editor' ]);
    
public function load_custom_post_content_editor($post) {
        // Check if the post type is 'post' or 'page'
        if (in_array($post->post_type, array('post', 'page'))) {
            $custom_post_content = get_post_meta($post->ID, 'post_content', true);
            if (!empty($custom_post_content)) {
                $post->post_content = $custom_post_content;
            }
        }
    }
add_action('wp_insert_post_data', [ $this, 'modify_post_data' ], 10, 2);

public function modify_post_data($data, $postarr) {
        // Check if the post type is allowed.
        if (in_array($data['post_type'], self::$allowed_post_types)) {
            $custom_post_content = get_post_meta($postarr['ID'], 'post_content', true);
            if (!empty($custom_post_content)) {
                $data['post_content'] = $custom_post_content;
            }
        }
        return $data;
    }
add_filter('block_editor_content', [ $this, 'filter_block_editor_content' ], 10, 2);

public function filter_block_editor_content($content, $post) {
        // Check if the post type is allowed.
        if ($post && in_array($post->post_type, self::$allowed_post_types)) {
            $custom_post_content = get_post_meta($post->ID, 'post_content', true);
            if (!empty($custom_post_content)) {
                $content = $custom_post_content;
            }
        }
        return $content;
    }

None of these successfully load the content from my custom field in the WordPress editor, even though a 'post_content' custom field exists with the block editor content code inside the field.

Here the rest of my working class which offloads the post content to a custom field called post_content when saving post/pages in the admin...

<?php
/**
 * Plugin Name: WP JSON Search
 * Description: The WP JSON Search plugin allows you to search your WordPress website by merging complete post content, custom fields, and taxonomies into a single JSON string, which is then stored in your post_content in wp_posts table.
 * Version: 1.0
 * Author: Josh Cranwell
 * Author URI: https://github.com/joshmoto
 */

class WP_JSON_Search {

    /**
     * @var array|string[] Allowed post types to save json search content.
     */
    private static array $allowed_post_types = ['post', 'page'];

    /**
     * WP_JSON_Search constructor.
     */
    public function __construct () {

        // Save post_content to custom meta field when saving a draft or publishing a post/page.
        add_action('save_post', [ $this, 'save_post_content' ], 10, 2);

        // Filter the content to get data from the custom meta field.
        add_filter('the_content', [ $this, 'filter_the_content' ]);

    }

    /**
     * Save post_content to custom meta field when saving a draft or publishing a post/page.
     * @param $post_id
     * @param $post
     * @return void
     */
    public function save_post_content($post_id, $post): void
    {

        // Check if the post type is allowed.
        if (in_array($post->post_type, self::$allowed_post_types)) {

            // Set the post_content to the custom meta field.
            $post_content = $post->post_content;
            update_post_meta($post_id, 'post_content', $post_content);
            $post->post_content = ''; // Empty the default post_content field.

            // Unhook this function so it doesn't loop infinitely.
            remove_action('save_post', [ $this, 'save_post_content' ]);

            // Update the post, which calls save_post again.
            wp_update_post($post);

            // Re-hook this function.
            add_action('save_post', [ $this, 'save_post_content' ]);

        }
    }

    /**
     * Filter the content to get data from the custom meta field.
     * @param $content
     * @return mixed
     */
    public function filter_the_content($content): mixed
    {

        // Get the current post.
        global $post;

        // Check if the post type is allowed.
        if ($post && in_array($post->post_type, self::$allowed_post_types)) {

            // Get the post_content from the custom meta field.
            $custom_post_content = get_post_meta($post->ID, 'post_content', true);
            if (!empty($custom_post_content)) {
                $content = $custom_post_content;
            }
        }

        // Return the content.
        return $content;
    }

}

new WP_JSON_Search();

If anyone has any suggestions about how I can filter the content in the editor to load data from a custom field that would be so helpful.


Solution

  • Gutenburg's editor uses WordPress's internal REST API. You can tap into that and manipulate the response being sent back.

    Add the below filters:

    // filter our rest post content
    add_filter('rest_post_content', function (array $content, string $type, int $post_id) {
    
        $content['raw'] = 'Updated content!';
    
        return $content;
    }, 10, 3);
    
    // filter the rest response
    add_filter('rest_post_dispatch', function (WP_Rest_Response $object) {
        if (
            !property_exists($object, 'data')
            || !array_key_exists('content', $object->data)
            || !array_key_exists('type', $object->data)
            || !array_key_exists('id', $object->data)
        ) {
            return $object;
        }
    
        $object->data['content'] = apply_filters(
            'rest_post_content',
            $object->data['content'],
            $object->data['type'],
            $object->data['id']
        );
    
        return $object;
    }, 10, 1);
    

    rest_post_dispatch is an internal WordPress filter, you can check the response and if all the data is there, apply a custom rest_post_content filter to manipulate your data before it gets sent to the Gutenburg editor!