3

I’m trying to add HTML wrappers around a block to create a clipping effect, something like the below code. It has been suggested this might be possible with the block save or block edit functions?

I have done a fair bit of experimenting with CSS clip-path and SVG clipPath and unfortunately they will not work for what I am trying to achieve as I need cross-browser support.

HTML:

<div class="transform-containter">
<div class="transform-right">
<div class="transform-left">
<div class="transform-content">
<div class="block-container">
BLOCK CONTENT HERE
</div>
</div>
</div>
</div>
</div>

CSS:

.transform-containter {
    width: 100%;
    height: auto;
    margin-top: 0;
    overflow-x: hidden;
    overflow-y: hidden;
}
.transform-right {
    position: relative;
    width: 110%;
    height: 100%;
    top: 0;
    left: -5%;
    -webkit-transform: rotate(2deg);
    -moz-transform: rotate(2deg);
    -ms-transform: rotate(2deg);
    -o-transform: rotate(2deg);
    transform: rotate(2deg);
    overflow: hidden;
    margin-top:2.5%;
}
.transform-left {
    position: relative;
    width: 110%;
    height: 100%;
    left: -5%;
    -webkit-transform: rotate(-4deg);
    -moz-transform: rotate(-4deg);
    -ms-transform: rotate(-4deg);
    -o-transform: rotate(-4deg);
    transform: rotate(-4deg);
    overflow: hidden;
    margin-top: -4%;
    margin-bottom: 3.5%;
}
.transform-content {
    width: 100%;
    height: 100%;
    -webkit-transform: rotate(2deg);
    -moz-transform: rotate(2deg);
    -ms-transform: rotate(2deg);
    -o-transform: rotate(2deg);
    transform: rotate(2deg);
    background-color: #cccccc;
    background-position: center;
    background-repeat: no-repeat;
    background-size: cover;
    margin: 2% 0 -2% 0;
    padding: 2em 10%;
}

Here is a codepen of the effect in raw HTML/CSS https://codepen.io/bearandpear/pen/VObzQZ

So essentially just trying to add the extra HTML div elements either side of the block output code.

Any help would be greatly appreciated. I’m not a developer, I’m pretty good with HTML, CSS and a little PHP, but completely green when it comes to Javascript/React…

1
  • note that you can create that HTML structure using only group blocks in the block editor, without writing any code. 5 group blocks, each with their class set.
    – Tom J Nowell
    Commented Aug 8, 2023 at 11:58

3 Answers 3

2

When registering a block we indicate: an edit property which defines how the block acts/displays in the editor, and a save property which is responsible for the final HTML of the block.

To modify these two functions from a block we need to use filter hooks. These hooks just need to be included inside a script in the editor.

The getSaveElement filter lets us modify the HTML output of the save property of the block. Using JSX:

const modifySaveHtml = (block, props, attributes) => {
    if (props.name !== "my-plugin/my-block") {
        return block;
    }

    return (
        <div className="transform-container">
            <div className="transform-right">
                <div className="transform-left">
                    <div className="transform-content">{block}</div>
                </div>
            </div>
        </div>
    );
};
wp.hooks.addFilter(
    "blocks.getSaveElement",
    "my-plugin/modifySaveHtml",
    modifySaveHtml
);

Using JS (ES5):

var createElement = wp.element.createElement;

var modifySaveHtml = function(block, props, attributes) {
    if (props.name !== "my-plugin/my-block") {
        return block;
    }

    return createElement(
        "div",
        { className: "transform-container" },
        createElement(
            "div",
            { className: "transform-right" },
            createElement(
                "div",
                { className: "transform-left" },
                createElement("div", { className: "transform-content" }, block)
            )
        )
    );
};
wp.hooks.addFilter(
    "blocks.getSaveElement",
    "my-plugin/modifySaveHtml",
    modifySaveHtml
);

The editor.BlockEdit filter modifies the HTML of the edit property of the block. This might not be necessary if you don't need to modify the HTML in the editor. Using JSX:

const modifyEditHtml = BlockEdit => {
    return props => {
        if (props.name !== "my-plugin/my-block") {
            return <BlockEdit {...props} />;
        }

        return (
            <div className="transform-container">
                <div className="transform-right">
                    <div className="transform-left">
                        <div className="transform-content">
                            <BlockEdit {...props} />
                        </div>
                    </div>
                </div>
            </div>
        );
    };
};
wp.hooks.addFilter(
    "editor.BlockEdit",
    "my-plugin/modifyEditHtml",
    modifyEditHtml
);

Using JS (ES5):

var createElement = wp.element.createElement;

var modifyEditHtml = function(BlockEdit) {
    return function(props) {
        if (props.name !== "my-plugin/my-block") {
            return createElement( BlockEdit, props );
        }

        return createElement(
            "div",
            { className: "transform-container" },
            createElement(
                "div",
                { className: "transform-right" },
                createElement(
                    "div",
                    { className: "transform-left" },
                    createElement(
                        "div",
                        { className: "transform-content" },
                        createElement(
                            BlockEdit,
                            props
                        )
                    )
                )
            )
        );
    };
};
wp.hooks.addFilter(
    "editor.BlockEdit",
    "my-plugin/modifyEditHtml",
    modifyEditHtml
);

Keep in mind that these filters will be applied to both new instances of the block and old ones. This means that any block which was created previously will show an "invalid content" message. This is because the filter modifies the block definition and it now expects the new HTML which is not there, as the block was created/saved before applying the filter.

When enqueuing your script (from PHP), remember to include the used dependencies. In the above code, wp-hooks package is used and wp-element as well in the non-JSX code.

function my_plugin_enqueue_editor() {

    wp_enqueue_script(
        'my-plugin-script', // name
        'path/to/my-plugin-script.js', // path
        array( // dependencies
            'wp-element',
            'wp-hooks',
        ),
        '1.0.0', // my-plugin version number
        true // enqueue in the footer.
    );

}
add_action( 'enqueue_block_editor_assets', 'my_plugin_enqueue_editor' );

Note: The JS(ES5) code is untested but I think it should work correctly.

13
  • This is great, thank you Alvaro. This all seems to make sense (and probably works perfectly), but due to my own inexperience I could't quite figure out how to get this to work when hooking into an existing plugin. I have however managed a work-around by building my own very simple container block plugin with all of the HTML wrappers needed (using innerBlocks and align-full), which I can insert the other blocks into. Commented May 20, 2019 at 11:31
  • @bearandpear You just need to add the code in the same script you are using to add your custom block. Can you share how you are adding that script (the PHP function)?
    – Alvaro
    Commented May 20, 2019 at 12:00
  • does this code go in the JS file or the PHP file? I was inserting it in the JS file which is called up in my plugin's PHP file... function bp_block_container_enqueue() { wp_enqueue_script( 'bp-block-container-script', plugins_url( 'bpblockcontainer.js', __FILE__ ) ); } add_action( 'enqueue_block_editor_assets', 'bp_block_container_enqueue' ); Commented May 20, 2019 at 14:54
  • @bearandpear the code from the answer goes in that JS file. But you need to modify your wp_enqueue_script call to include the 'wp-hooks' dependency. When using any of the Gutenberg packages (wp.editor, wp.blocks, etc.) you need to include those dependencies in your script enqueue (remember that the JS object wp.hooks belongs to the dependency wp-hooks). See an example of adding a Gutenberg dependency here.
    – Alvaro
    Commented May 20, 2019 at 17:32
  • I have added 'wp-hooks' to the wp_enqueue_script like this... function bp_block_container_enqueue() { wp_enqueue_script( 'bp-block-container-script', plugins_url( 'bpblockcontainer.js', __FILE__ ) ); } add_action( 'enqueue_block_editor_assets', 'bp_block_container_enqueue' ); add_action( 'wp-hooks', 'bp_block_container/modifySaveHtml' ); add_action( 'wp-hooks', 'bp_block_container/modifyEditHtml' ); but I keep getting this in the console... 'Uncaught SyntaxError: Unexpected token <' I am clearly doing something wrong in the JS? Commented May 20, 2019 at 18:45
0

You can create divs inside divs (or different elements) in the Gutenberg edit/save function. Like so:

createElement( "div",
               {className: "transform-containter"},
                createElement( "div",
                               {className: "transform-right"},
                                createElement( "div",
                                                {className: "transform-left"},
                          [AND SO ON...]
                               YOUR BLOCK CONTENT
                                )
                )
)

I think you try to write your own block, or am I wrong?

2
  • Thank you for this. I am actually trying to add these elements to an existing block, as I am not fluent enough in javascript/react to create one from scratch. Is there a way to add this code to an existing block externally, or would this only work if I write one from scratch? Commented May 17, 2019 at 10:27
  • Sorry, I don't know a way to hook into a block or extend it anyhow.
    – moped
    Commented May 17, 2019 at 11:41
0

You could also wrap your gutenberg block via WP PHP filter:

<?php

add_filter( 'render_block', [$this, 'wp_gutenberg_wrap_block'], 10, 2 );

function wp_gutenberg_wrap_block( $block_content, $block ) {
    $align_class = 'default';
    $alignment   = $block['attrs']['align'] ?? 'default';

    if ( $alignment === 'full' ) {
        $align_class = 'alignfull';
    }

    if ( $alignment === 'wide' ) {
        $align_class = 'alignwide';
    }

    $wrapper = "<section class='block_wrapper $align_class'>";
    $wrapper .= $block_content;
    $wrapper .= '</section>';

    return $wrapper;
}

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.