How can I see a list of pages and post where my custom Gutenberg block is used?

One can e.g. use the general search in the /wp-admin backend to find some text within the post’s content that stores the blocks:

We can search for a prefixed block name wp:my-plugin/my-block within the posts:

example.com/wp-admin/edit.php
?s=wp:my-plugin%2Fmy-block%20&post_type=post

where we have an extra space (url encoded as %20and / as %2F) after the block’s name, as the first part of it would be stored as <!-- wp:my-plugin/my-block --> or with attributes <!-- wp:my-plugin/my-block {...} --> in the post’s content.

The front-end search works as well, but without the post type filtering as in the backend (unless adjusted with a plugin):

example.com
?s=wp:my-plugin%2Fmy-block%20

This block search might not be 100% accurate (e.g. if you blog about block names) but it might give you a good enough estimate in most cases.

More accurate searching

We note that searching for <!-- wp:my-plugin/my-block with:

example.com
?s=<%21--%20wp:my-plugin%2Fmy-block%20

will be split up in two words in the generated SQL:

WHERE 1=1
AND (((wp_posts.post_title LIKE '%<!--%')
OR (wp_posts.post_excerpt LIKE '%<!--%')
OR (wp_posts.post_content LIKE '%<!--%'))
AND ((wp_posts.post_title LIKE '%wp:my-plugin/my-block %')
OR (wp_posts.post_excerpt LIKE '%wp:my-plugin/my-block %')
OR (wp_posts.post_content LIKE '%wp:my-plugin/my-block %')))
...

but we can avoid it with the sentence parameter:

example.com
?s=<%21--%20wp:my-plugin%2Fmy-block&sentence=1

and get a search query like:

WHERE 1=1
AND (((wp_posts.post_title LIKE '%<!-- wp:my-plugin/my-block %')
OR (wp_posts.post_excerpt LIKE '%<!-- wp:my-plugin/my-block %')
OR (wp_posts.post_content LIKE '%<!-- wp:my-plugin/my-block %')))
...

With code

Alternatively we could use a custom WP_Query search like:

WP_Query( array( 
    's'         => '<!-- wp:my-plugin/my-block ', 
    'sentence'  => 1, 
    'post_type' => array( 'post', 'page' ),
) );

or run has_block( 'my-plugin/my-block', $post_content ) on all the relevant post content for the given block name or use parse_blocks( $post_content ) if you need more info from it.

Reusable blocks

We should note that reusable blocks are stored like:

<!-- wp:block {"ref":23495} /-->

in the post’s content, so we might look into the wp_block post type that stores it:

example.com/wp-admin/edit.php
?s=<%21--%20wp:my-plugin%2Fmy-block%20&post_status=all&post_type=wp_block&sentence=1

Simple Block Type Search Plugin

To make things easier I’ve created a plugin that adds a dropdown filter for registered block types, under each list table in the admin:

to simplify the search that is automatically added when filtering:

Create a plugin file and activate:

<?php 
/* Plugin Name: Simple Block Type Search
 * Plugin URI: https://wordpress.stackexchange.com/a/392175/26350 
 */
add_action( 'restrict_manage_posts', 'simple_block_type_search', 10, 2 );

function simple_block_type_search ( $post_type, $which ) {
    if ( ! use_block_editor_for_post_type ( $post_type ) ) {
        return;
    } 
    $block_types = \WP_Block_Type_Registry::get_instance()->get_all_registered();
    $options = array_reduce( $block_types, function( $options, $block_type ) {
        $val="!-- wp:" . str_replace( 'core/', '', $block_type->name ) . ' ';
        return $options . sprintf ( '<option value="%s" %s>%s</option>',
            esc_attr( $val ),
            selected( get_query_var( 's' ), $val, false ),
            esc_html( $block_type->name )
        );
    }, '' );
    printf ( '<select name="s"><option value="">%s</option>%s</select>
              <input type="hidden" name="sentence" value="1"/>', 
         esc_html__( 'Block Type Search', 'simple_block_type_search' ),
         $options            
    );
}

To get all registered block types, we used:

\WP_Block_Type_Registry::get_instance()->get_all_registered()

and to only display the dropdown on supported post types we used:

use_block_editor_for_post_type()

Here we used the built-in search feature and the user interface of the admin backend. That’s why the plugin is so few lines of code.

Leave a Comment