Just updated my Wordpress environment to the latest version and saw the Gutenberg editor. It took some digging around but I am able to find almost all of the settings (such as custom fields) I used in the classic editor in Gutenberg, except for "Custom body class" and "Custom post class" in the Layout Settings panel. Attached is the image of the settings I'm looking for. I know I can use hooks to add custom body classes to any page/post in functions.php but this approach isn't end user friendly.

The only solution I can think of at the moment is to install the Classic Editor plugin so I can use it to add custom body/post classes when needed. But I don't want to install the plugin just for that use case. So far, I have no problem with the Gutenberg editor. I think it will be very useful for end users who aren't familiar with html/css to be able to create reasonable layouts on their own. I really just want to be able to set custom body/post class on the fly like before. I have not been able to find any answer on the internet.

layout settings panel in old editor

1 Answer 1


For a very basic implementation of adding a text input to add body classes(would also work for adding a second field for post classes if necessary) to pages/posts, you could do the following:

  1. Register a custom field with register_post_meta - I'll use an empty string for the first param, post_type so it applies to all. Also note that we want to make use of the REST API, so the value is usable in Gutenberg by passing true to show_in_rest:
// File: themeslug/functions.php
// Register the 'themeslug_add_body_class' post meta.
add_action( 'after_setup_theme', function() {
    register_post_meta( '', 'themeslug_add_body_class', array(
        'show_in_rest' => true,
        'single' => true,
        'type' => 'string',
    ) );
} );
  1. Add a custom panel called Layout Settings with a text input control, which is linked to the value of themeslug_add_body_class. We will add this to Document Settings in Gutenberg. To do this we will use the SlotFill called PluginDocumentSettingPanel. I'll use the basic example from the Block Editor Handbook, so refer to the Tutorials section for a more in depth explanation of what everything in the JS code is doing.
// File: themeslug/assets/js/editor.js
( function( wp ) {
    var { registerPlugin } = wp.plugins;
    var { PluginDocumentSettingPanel } = wp.editPost;
    var el = wp.element.createElement;
    var Text = wp.components.TextControl;
    var withSelect = wp.data.withSelect;
    var withDispatch = wp.data.withDispatch;

    var mapSelectToProps = function( select ) {
        return {
            metaFieldValue: select( 'core/editor' )
                .getEditedPostAttribute( 'meta' )
                [ 'themeslug_add_body_class' ],

    var mapDispatchToProps = function( dispatch ) {
        return {
            setMetaFieldValue: function( value ) {
                dispatch( 'core/editor' ).editPost(
                    { meta: { themeslug_add_body_class: value } }

    var MetaBlockField = function( props ) {
        return el( Text, {
            label: 'Custom Body Classes',
            value: props.metaFieldValue,
            onChange: function( content ) {
                props.setMetaFieldValue( content );
        } );

    var MetaBlockFieldWithData = withSelect( mapSelectToProps )( MetaBlockField );
    var MetaBlockFieldWithDataAndActions = withDispatch( mapDispatchToProps )( MetaBlockFieldWithData );

    registerPlugin( 'theme-slug-add-body-class', {
        render: function() {
            return el( PluginDocumentSettingPanel,
                    name: 'theme-slug-add-body-class',
                    title: 'Layout Settings',
                    className: "theme-slug-custom-body-class",
                    icon: '',
                el( 'div',
                    { className: 'theme-slug-add-body-class-content' },
                    el( MetaBlockFieldWithDataAndActions )
    } );
} )( window.wp );
  1. Enqueue the JS script - to do this we will hook into enqueue_block_editor_assets, and use wp_enqueue_script like any other JS file. For script deps I'll just list them manually for simplicity:
// File: themeslug/functions.php
// Enqueue the JS for gutenberg.
add_action( 'enqueue_block_editor_assets', function() {
        get_theme_file_uri( '/assets/js/editor.js' ),
        [ 'wp-plugins', 'wp-data', 'wp-components', 'wp-edit-post', 'wp-element', 'wp-compose' ],
} );
  1. Now we have the meta registered, and our custom control/script enqueued and loaded in Gutenberg, so when visiting the editor we should see the Layout Settings panel added to Document Settings with our text field added under it:

enter image description here

The last part then would be to filter body_class with the user's input that is saved in the meta:

// File: themeslug/functions.php
// Dynamically add body class based on post meta saved.
add_filter( 'body_class', function( $classes ) {
    $body_classes = get_post_meta( get_the_ID(), 'themeslug_add_body_class', true );
    if ( '' !== $body_classes ) {
        $body_classes = array_map( 'esc_attr', explode( ' ', $body_classes ) );
        $classes = array_merge( $classes, $body_classes );
    return $classes;
} );

This allows for multiple classes added to body, which are space separated, but you can handle logic however your want for that obviously. You can extend this to add a second field for custom classes to be added as well. Instead of filtering body_class you could use post_class for that.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.