Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Wrapping aligned Gutenberg blocks with additional div on a WordPress website front-end.
<?php
// IMPORTANT UPDATE 20190307:
// Since WordPress 5.0.0 we can actually use much simpler solution:
/**
* Applies wrapper div around aligned blocks.
*
* Copy this function into your WordPress theme's `functions.php` file
* and change the `themeprefix` accordingly.
*
* @see https://developer.wordpress.org/reference/hooks/render_block/
* @link https://codepen.io/webmandesign/post/gutenberg-full-width-alignment-in-wordpress-themes
*
* @param string $block_content The block content about to be appended.
* @param array $block The full block, including name and attributes.
*/
function themeprefix_wrap_alignment( $block_content, $block ) {
if ( isset( $block['attrs']['align'] ) && in_array( $block['attrs']['align'], array( 'wide', 'full' ) ) ) {
$block_content = sprintf(
'<div class="%1$s">%2$s</div>',
'align-wrap align-wrap-' . esc_attr( $block['attrs']['align'] ),
$block_content
);
}
return $block_content;
}
add_filter( 'render_block', 'themeprefix_wrap_alignment', 10, 2 );
// OLD CODE (USE BETTER SOLUTION ABOVE):
/**
* Applies wrapper div around aligned blocks.
*
* This is a front-end solution only.
* In admin, blocks are already being wrapped and we can use attribute
* selectors of `[data-align="$alignment"]` in our editor stylesheet.
*
* Copy this function into your WordPress theme's `functions.php` file
* and change the `themeprefix` accordingly.
*
* @link https://codepen.io/webmandesign/post/gutenberg-full-width-alignment-in-wordpress-themes
*
* @param string $content Post content.
*/
function themeprefix_wrap_alignment( $content = '' ) {
// Requirements check
if ( ! is_callable( 'has_blocks' ) || ! has_blocks( $content ) ) {
return $content;
}
// Vars
$current_block = '';
$content_lines = explode( PHP_EOL, $content );
$alignments = (array) apply_filters( 'themeprefix_wrap_alignment/alignments', array( 'full', 'wide' ) );
// Processing
foreach ( $content_lines as $line_number => $line_content ) {
if ( false === strpos( $line_content, '<!-- wp:' ) && false === strpos( $line_content, '<!-- /wp:' ) ) {
// No block definition HTML comment? Do not process this line.
continue;
}
// Allow bypassing the line with a filter hook.
$line_content_pre = apply_filters( 'themeprefix_wrap_alignment/line_content_pre', false, $line_content, $line_number );
if ( is_string( $line_content_pre ) ) {
$content_lines[ $line_number ] = $line_content_pre;
continue;
}
// Get alignment if set.
preg_match( '/"align":"([^"]*)"/i', $line_content, $alignment );
if ( isset( $alignment[1] ) ) {
$alignment = $alignment[1];
} else {
$alignment = '';
}
if ( in_array( $alignment, $alignments ) ) {
/**
* Found a block with desired alignment definition?
* Do this:
* - get and remember block name/key in $current_block variable,
* - set a wrapper CSS class,
* - open our wrapper div.
*/
preg_match( '/wp:(\S+)/', $line_content, $current_block );
if ( isset( $current_block[1] ) ) {
$current_block = $current_block[1];
$class = sprintf(
(string) apply_filters( 'themeprefix_wrap_alignment/class', 'align-wrap align-wrap-%s', $current_block, $alignment ),
sanitize_title( $alignment )
);
$line_content = str_replace(
'<!-- wp:',
'<div class="' . esc_attr( $class ) . '">' . PHP_EOL . '<!-- wp:',
$line_content
);
} else {
$current_block = '';
}
} elseif ( ! empty( $current_block ) && false !== strpos( $line_content, '<!-- /wp:' . $current_block . ' -->' ) ) {
/**
* Have a block name/key saved and found a closing comment for that block?
* Do this:
* - close our wrapper div,
* - reset the $current_block variable.
*/
$line_content = str_replace(
'<!-- /wp:' . $current_block . ' -->',
'<!-- /wp:' . $current_block . ' -->' . PHP_EOL . '</div><!-- /.align-wrap -->',
$line_content
);
$current_block = '';
}
// Replace original line content with modified one.
$content_lines[ $line_number ] = $line_content;
}
// Output
return implode( PHP_EOL, $content_lines );
} // /themeprefix_wrap_alignment
// Hook before the `do_blocks` is hooked!
add_filter( 'the_content', 'themeprefix_wrap_alignment', 8 );
@webmandesign

This comment has been minimized.

Copy link
Owner Author

@webmandesign webmandesign commented Aug 16, 2018

Applying wrapper div around aligned blocks

This is a front-end solution only. In admin, blocks are already being wrapped and we can use attribute CSS selectors of [data-align="$alignment"] (where $alignment could be of left, center, right, wide or full value) in our editor stylesheet.

Default functionality

By default the code:

  • Works with full and wide aligned blocks only. This can be modified using themeprefix_wrap_alignment/alignments filter hook, though.
  • Wraps blocks in an additional div.align-wrap.align-wrap-$alignment div, where $alignment could be of full or wide value. The class can be modified using themeprefix_wrap_alignment/class filter hook.

Info & examples

For examples and information on styling please read a dedicated article.

How to apply?

Copy this PHP function into your WordPress theme's functions.php file and change the themeprefix appropriately.

Alternative version

Alternative version of the function actually wraps all content into div.content-section chunks splitting on full/wide aligned blocks. Thus creating similar content structure as on Medium.com.


Created by Oliver at WebManDesign.eu | Licensed under the terms of GPL

@chrisvanpatten

This comment has been minimized.

Copy link

@chrisvanpatten chrisvanpatten commented Aug 21, 2018

Nice stuff! I'm doing something very similar but using QueryPath, which smooths over a lot of the funkiness with parsing HTML. Here's my version.

@webmandesign

This comment has been minimized.

Copy link
Owner Author

@webmandesign webmandesign commented Aug 22, 2018

@chrisvanpatten
Wou, that looks superclean! Thank you for sharing. I wanted to create a function that should work everywhere without any additional libraries. But I will surely have a look at QueryPath as it seems to be very interesting library. Thanks again for sharing both QueryPath info and your code!

@BinaryMoon

This comment has been minimized.

Copy link

@BinaryMoon BinaryMoon commented Aug 25, 2018

Another option would be to use javascript to wrap anything with .alignfull class.

Since it's purely presentational and your site would still work with js disabled this may be a simpler option.

A simple method would be: https://plainjs.com/javascript/manipulation/wrap-an-html-structure-around-an-element-28/

@webmandesign

This comment has been minimized.

Copy link
Owner Author

@webmandesign webmandesign commented Aug 27, 2018

@BinaryMoon Thank you for your input. Yes, JavaScript solution was actually my first bet. But as I didn't like the sudden "jump" in .alignfull elements display caused by JS applying the wrapper only after the page was loaded, I've moved to PHP which prevents such behavior. Besides, the PHP version works with JS disabled too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment