In my last post, I showed how to load a specific block style in a different block and promised that I will show you how exactly I used it for the latest posts block. Since the “read more” link on this block is, by default, just a plain text link, I want to modify it to be styled as a regular button without needing to add custom CSS to style it this way.

I’m a fan of DOMDocument when it comes to add specific HTML at a specific position. Thus, I used it here. First I select every list item, as every latest post is within its own list item. Inside this list item, there are potentially multiple links, which I iterate through. In my case, I have only enabled the link of the title, so I explicitly check for the existence of the class wp-block-latest-posts__post-title and ignore this link element. If you also link your thumbnail to the post, you may need to extend this check.

After that, I use the link of the original “read more” link and replace its markup with a custom button(s) block.

And last but not least, as seen in my previous post, I enqueue the button block stylesheet to make sure the custom added “read more” button is properly designed.

This is what the code looks like in the end:

/**
 * Add a read more link as button and remove possibly existing ones.
 * 
 * @param	string	$block_content Block content
 * @return	string Updated block content
 */
function my_set_read_more_link( string $block_content ): string {
	\libxml_use_internal_errors( true );
	
	$dom = new \DOMDocument();
	$dom->loadHTML(
		'<html><meta charset="utf-8">' . $block_content . '</html>',
		LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD
	);
	
	foreach ( $dom->getElementsByTagName( 'li' ) as $list_element ) {
		$link = '';
		
		foreach ( $list_element->getElementsByTagName( 'a' ) as $anchor ) {
			if ( ! \str_contains( $anchor->getAttribute( 'class' ), 'wp-block-latest-posts__post-title' ) ) {
				continue;
			}
			
			$link = $anchor->getAttribute( 'href' );
			break;
		}
		
		if ( ! empty( $link ) ) {
			$template = \sprintf(
				'<div class="wp-block-buttons">
					<div class="wp-block-button is-read-more-button"><a class="wp-block-button__link wp-element-button" href="%1$s">%2$s</a></div>
				</div>',
				$link,
				\esc_html__( 'Read more', 'my-textdomain' )
			);
			$read_more_dom = new DOMDocument();
			$read_more_dom->loadHTML(
				'<html><meta charset="utf-8">' . $template . '</html>',
				LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD
			);
			
			foreach ( $list_element->getElementsByTagName( 'div' ) as $div ) {
				if ( ! \str_contains( $div->getAttribute( 'class' ), 'wp-block-latest-posts__post-excerpt' ) ) {
					continue;
				}
				
				foreach ( $div->getElementsByTagName( 'a' ) as $anchor ) {
					$div->removeChild( $anchor );
				}
				
				$read_more_node = $dom->importNode( $read_more_dom->documentElement->firstChild->nextSibling, true ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
				$div->appendChild( $read_more_node );
			}
		}
	}
	
	$block_content = $dom->saveHTML( $dom->documentElement->firstChild->nextSibling ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
	
	\wp_enqueue_style( 'wp-block-button' );
	\libxml_use_internal_errors( false );
	
	return $block_content;
}

\add_filter( 'render_block_core/latest-posts', 'my_set_read_more_link' );
Code language: PHP (php)

Leave a Reply

Your email address will not be published. Required fields are marked *

To respond on your own website, enter the URL of your response which should contain a link to this post's permalink URL. Your response will then appear (possibly after moderation) on this page. Want to update or remove your response? Update or delete your post and re-enter your post's URL again. (Learn more about webmentions)