0

I need to know if the first block is an image and if it's aligned right or left. I printed the $first_block_attrs variable and can see the output is Array ( [align] => center [id] => 450 [sizeSlug] => large [linkDestination] => none ) but am not sure how to check if the [align] attribute is either 'left' or 'right'. Or how to check if it is not 'center' or even unset. Any help is appreciated!

if ( has_blocks( $post->post_content ) ) {
    $blocks = parse_blocks( $post->post_content );
    if ( $blocks[0]['blockName'] === 'acf/slideshow-block' || $blocks[0]['blockName'] === 'core/image' || is_page(array(9,11)) ) {
        if ($blocks[0]['blockName'] === 'core/image') {
            $first_block_attrs = $blocks[0]['attrs'];
            // Testing if 'align' is set
            if(array_key_exists('align', $first_block_attrs)) {
                //print_r($first_block_attrs);
            }
            // This is what I need help with
            if ( 'image block is aligned right or left' ) {
            }
        }
    }
}
8
  • What feature or problem are you trying to solve with this? Can you not use the block rendering filters? – Tom J Nowell Apr 16 at 15:56
  • I'm needing to set a CSS class on a different element based on whether there's an image floated right or left at the beginning of the body copy. If this check returns true, I'll set a different class than if there is no image or if the image is center aligned. I'm not familiar with block rendering filters. How would that work exactly? – Greg Apr 16 at 17:20
  • Depends on what the class does, can you give the non-generic version of the problem? Left or right aligned image blocks already have HTML classes applied that can be used to select either the image or adjacent elements. There's likely a block based solution too, as well as other CSS based solutions, but you've made your problem too generic to solve with an optimal answer. I could write a solution to the exact question you wrote but it would take me hours to write and it would not be nice, and i know for a fact there are much easier, simpler, nicer solutions if only I knew the actual problem – Tom J Nowell Apr 16 at 17:54
  • E.g. .entry-content > .wp-block-image:first-child + * { outline: 5px solid hotpink; } matches the second element in post content when the first element is an image block, which is easier than what you've asked and would fix a lot of styling issues ( especially if the class you're trying to add just happens to be align to the other side ). It can be extended with class selectors to be even more specific. But such an answer does not solve your question. – Tom J Nowell Apr 16 at 18:18
  • If the image has not been given an alignment there is no way for me to target it especially for an element further down the page. This is the markup I'm currently getting: <figure class="wp-block-image size-large">. If the image is aligned left or right I need a totally different element on the page to receive a class so I can apply different formatting. I don't believe this can be accomplished with CSS alone. – Greg Apr 16 at 19:11
1

Your problem can be solved using CSS and a small filter. Your proposed solution is not viable.

You can check the attributes of some blocks but changing those attributes will not re-render the block if its HTML was generated by javascript. This means the majority of the standard blocks cannot be modified this way, and modifying the class attribute will not change the markup on the frontend.

However, it is not necessary. CSS can handle every situation using the various CSS3+ selectors. Since you won't share the specifics of your problem, I've been forced to brute force the solution by detailing every possible combination.

Adding An Alignment Data Attribute To Image Blocks

But first, left and right aligned images don't have a class on their parent container, only fullwidth and wide images, so we're going to fix that by adding a data attribute:

/**
 * Ensure all image blocks have an alignment class.
 *
 * @param string $block_content The block content about to be appended.
 * @param array  $block         The full block, including name and attributes.
 * @return string Modified block content.
 */
function tomjn_add_align_class( $block_content, $block ) {
    $alignment = 'none';
    if ( ! empty( $block['attrs']['align'] ) ) {
        $alignment = $block['attrs']['align'];
    }
    $content = str_replace(
        'class="wp-block-image',
        'data-align="' . esc_attr( $alignment ) .'" class="wp-block-image',
        $block_content
    );
    return $content;
}
add_filter( 'render_block_core/image', 'tomjn_add_align_class', 10, 2 );

This allows us to use pure CSS for the rest. Note that we have no way of knowing which block is next when using the block rendering filters, so this can't be used to implement the original proposed solution. This would also lead to problems when more than one post is being rendered, e.g. if the last block of a post is an image, the first block of the next post would incorrectly get the class.

Styling The Blocks

Selecting A Block Immediately After An Image Block

.wp-block-image + * {
    color: hotpink;
}

enter image description here

Selecting A Block Imediatley After An Image Block That The First Block In A Post

.entry-content > .wp-block-image:first-child + * {
    color: hotpink;
}

enter image description here

Note the > is necessary, without it the first image blocks inside nested blocks will also be selected. Adjust .entry-content to the class that contains your content.

Selecting A Block Immediately After A Left Aligned Image Block

.wp-block-image[data-align="left"] + * {
    color: hotpink;
}

enter image description here

Selecting A Block Immediately After A Right Aligned Image Block

.wp-block-image[data-align="right"] + * {
    color: hotpink;
}

enter image description here

Selecting A Block Immediately After A Center Aligned Image Block

.wp-block-image[data-align="center"] + * {
    color: hotpink;
}

enter image description here

Selecting A Block Immediately After A Wide Aligned Image Block

.wp-block-image.alignwide + * {
    color: hotpink;
}

enter image description here

Selecting A Block Immediately After A Full Width Image Block

.wp-block-image.alignfull + * {
    color: hotpink;
}

enter image description here

Selecting A Block Immediately After An Image Block With No Alignment

.wp-block-image[data-align="none"] + * {
    color: hotpink;
}

enter image description here


And so on, you can expand this further:

  • Using ~ instead of + will select all blocks rather than the next adjacent block
  • You can change + * with a more specific selector e.g. .wp-block-image[data-align="none"] + ul { will select all lists that come after an image block with no alignment
  • You can chain them together, e.g. you can select not the next block but the one after that with .wp-block-image[data-align="none"] + * + * {

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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