Last active
September 9, 2020 17:14
-
-
Save webmandesign/5b50d521e085198dce4eadb6864eb5a3 to your computer and use it in GitHub Desktop.
Wrapping aligned Gutenberg blocks with additional div on a WordPress website front-end.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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 ); |
@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
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/