Adding Schema.org Microdata to Accordion Block FAQs

Had a client come to me last week. Their SEO guy was breathing down their neck because the beautiful new FAQs page, built with the native WordPress Accordion block, was invisible to Google as a proper FAQ section. No rich snippets, no special treatment in search results. The page looked great, but from a search engine’s perspective, it was just a bunch of random divs. The core of the problem? The default block doesn’t output the Accordion block schema needed for search crawlers to make sense of it.

My first thought, and maybe yours too, would be to reach for a plugin. There are dozens of schema or “structured data” plugins out there. Here’s the kicker: most of them want you to use their custom FAQ block. The client had just spent a week perfecting the styling of the core Accordion block. Telling them to scrap it and start over wasn’t an option. The other “quick fix” that crossed my mind was to use JavaScript to jam the attributes in on the front end. Trust me on this. Don’t do it. It’s a fragile, messy solution that can be a performance killer.

The Right Way: Filter the Block on the Server

Since WordPress 6.2, we have the WP_HTML_Tag_Processor. This class is a godsend. It lets us parse and modify the HTML of a block right before it’s sent to the browser. No JavaScript hacks, no heavy plugins. We just hook into the block’s rendering, find our specific accordion, and inject the necessary Schema.org microdata. It’s clean, efficient, and future-proof. It’s the way you’re supposed to handle this stuff now.

This is the exact approach I used, building on a great concept I saw over at the WordPress Developer Blog. First, you need to identify the specific accordion you want to modify. The easiest way is to give it a unique CSS class. I used is-faqs, which you can add in the block’s “Advanced” panel. Then, you just drop this filter into your functions.php or a custom plugin:

add_filter( 'render_block_core/accordion', 'projectslug_render_accordion_faqs' );

function projectslug_render_accordion_faqs( $content ): string
{
	$processor = new WP_HTML_Tag_Processor( $content );

	// Bail early if there's no Accordion block with the `.is-faqs` class.
	if (
		! $processor->next_tag( [ 'class_name' => 'wp-block-accordion' ] )
		|| ! $processor->has_class( 'is-faqs' )
	) {
		return $processor->get_updated_html();
	}

	// Add attributes to wrapping accordion block.
	$processor->set_attribute( 'itemscope', true );
	$processor->set_attribute( 'itemtype', 'https://schema.org/FAQPage' );

	// Loop through accordion items and add attributes.
	while ( $processor->next_tag( [ 'class_name' => 'wp-block-accordion-item' ] ) ) {
		$processor->set_attribute( 'itemscope', true );
		$processor->set_attribute( 'itemprop', 'mainEntity' );
		$processor->set_attribute( 'itemtype', 'https://schema.org/Question' );

		// Add attributes to the title element.
		if ( $processor->next_tag( [ 'class_name' => 'wp-block-accordion-heading__toggle-title' ] ) ) {
			$processor->set_attribute( 'itemprop', 'name' );
		}

		// Add attributes to the panel.
		if ( $processor->next_tag( [ 'class_name' => 'wp-block-accordion-panel' ] ) ) {
			$processor->set_attribute( 'itemscope', true );
			$processor->set_attribute( 'itemprop', 'acceptedAnswer' );
			$processor->set_attribute( 'itemtype', 'https://schema.org/Answer' );

			// Add attribute to first paragraph.
			if ( $processor->next_tag( 'p' ) ) {
				$processor->set_attribute( 'itemprop', 'text' );
			}
		}
	}

	return $processor->get_updated_html();
}

So, What’s the Point?

The point is to stop thinking about every problem as something that needs another plugin. More often than not, a few lines of well-placed code are a much better solution. This approach is incredibly lightweight, keeps you in control of your HTML, and doesn’t lock you into a third-party block system you can’t easily style or migrate away from. It’s about solving the specific problem without creating three new ones. And that was it. The SEO guy was happy, the client’s page looked the same, and Google could finally understand their content.

Look, this stuff gets complicated fast. If you’re tired of debugging someone else’s mess and just want your site to work, drop my team a line. We’ve probably seen it before.

Leave a Reply

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