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 *