# Block Usage Report Under Tools

> Adds a Tools > Block Usage screen counting how many posts and pages use each block, with a link to the content using it, so you know which blocks and plugins are safe to remove.

- Type: PHP
- Runs: Admin only
- Category: [Block Editor](https://wpide.com/library/category/gutenberg/)
- Tags: blocks, audit, tools
- Author: WPIDE Team
- Installs: 0
- Updated: 2026-10-28
- Page: https://wpide.com/library/block-usage-report/

## Code

```php
add_action( 'admin_menu', function () {
    add_management_page( 'Block Usage', 'Block Usage', 'manage_options', 'wpide-block-usage', function () {
        global $wpdb;

        if ( isset( $_GET['rescan'] ) && check_admin_referer( 'wpide_block_rescan' ) ) {
            delete_transient( 'wpide_block_usage' );
        }

        $usage = get_transient( 'wpide_block_usage' );
        if ( false === $usage ) {
            $usage = array();
            $rows  = $wpdb->get_results(
                "SELECT ID, post_content FROM {$wpdb->posts} WHERE post_status IN ('publish','draft','private','future','pending')
                AND post_type NOT IN ('revision','attachment','nav_menu_item','customize_changeset') AND post_content LIKE '%<!-- wp:%' ORDER BY ID DESC LIMIT 2000"
            );
            foreach ( $rows as $row ) {
                preg_match_all( '/<!--\s+wp:([a-z0-9-]+\/)?([a-z0-9-]+)[\s\/]/', $row->post_content, $matches, PREG_SET_ORDER );
                $seen = array();
                foreach ( $matches as $match ) {
                    $name = ( $match[1] ? $match[1] : 'core/' ) . $match[2];
                    $usage[ $name ]['uses'] = ( $usage[ $name ]['uses'] ?? 0 ) + 1;
                    if ( ! isset( $seen[ $name ] ) ) {
                        $usage[ $name ]['posts'] = ( $usage[ $name ]['posts'] ?? 0 ) + 1;
                        $usage[ $name ]['example'] = $usage[ $name ]['example'] ?? (int) $row->ID;
                        $seen[ $name ] = true;
                    }
                }
            }
            uasort( $usage, function ( $a, $b ) {
                return $b['posts'] <=> $a['posts'];
            } );
            set_transient( 'wpide_block_usage', $usage, HOUR_IN_SECONDS );
        }

        echo '<div class="wrap"><h1>Block Usage</h1>';
        printf( '<p><a class="button" href="%s">Rescan</a></p>', esc_url( wp_nonce_url( admin_url( 'tools.php?page=wpide-block-usage&rescan=1' ), 'wpide_block_rescan' ) ) );
        echo '<table class="widefat striped"><thead><tr><th>Block</th><th>Posts using it</th><th>Total uses</th><th>Example</th></tr></thead><tbody>';
        foreach ( $usage as $name => $data ) {
            $registered = WP_Block_Type_Registry::get_instance()->is_registered( $name );
            printf(
                '<tr><td><code>%s</code>%s</td><td>%d</td><td>%d</td><td><a href="%s">%s</a></td></tr>',
                esc_html( $name ),
                $registered ? '' : ' <span style="color:#b32d2e">(not registered)</span>',
                (int) $data['posts'],
                (int) $data['uses'],
                esc_url( get_edit_post_link( $data['example'] ) ),
                esc_html( get_the_title( $data['example'] ) ? get_the_title( $data['example'] ) : '#' . $data['example'] )
            );
        }
        echo '</tbody></table></div>';
    } );
} );
```

## Notes

Scans up to 2,000 published and draft items and caches the result for an hour; click "Rescan" to refresh.

## How to use it

Install the free WPIDE plugin (https://wordpress.org/plugins/wpide/), find "Block Usage Report Under Tools" in its snippet library and add it in one click; or create a new PHP snippet in WPIDE (or any code snippets plugin) and paste the code above. More snippets: https://wpide.com/library/
