# Orphaned Metadata Cleanup Tool

> Adds Tools > Orphaned Metadata, which counts post, comment, term and user meta rows whose post, comment, term or user no longer exists, and removes them after you confirm.

- Type: PHP
- Runs: Admin only
- Category: [Performance](https://wpide.com/library/category/performance/)
- Tags: database, cleanup, metadata
- Author: WPIDE Team
- Installs: 0
- Updated: 2026-10-28
- Page: https://wpide.com/library/perf-orphaned-meta-cleanup/

## Code

```php
add_action( 'admin_menu', function () {
    add_management_page( 'Orphaned Metadata', 'Orphaned Metadata', 'manage_options', 'wpide-orphaned-meta', function () {
        global $wpdb;

        $tables = array(
            'Post meta'    => array( $wpdb->postmeta, 'post_id', $wpdb->posts, 'ID' ),
            'Comment meta' => array( $wpdb->commentmeta, 'comment_id', $wpdb->comments, 'comment_ID' ),
            'Term meta'    => array( $wpdb->termmeta, 'term_id', $wpdb->terms, 'term_id' ),
            'User meta'    => array( $wpdb->usermeta, 'user_id', $wpdb->users, 'ID' ),
        );

        if ( isset( $_POST['wpide_clean_orphans'] ) && check_admin_referer( 'wpide_clean_orphans' ) && current_user_can( 'manage_options' ) ) {
            $deleted = 0;
            foreach ( $tables as list( $meta, $fk, $parent, $pk ) ) {
                $deleted += (int) $wpdb->query( "DELETE m FROM $meta m LEFT JOIN $parent p ON p.$pk = m.$fk WHERE p.$pk IS NULL" );
            }
            wp_cache_flush();
            printf( '<div class="notice notice-success"><p>%s</p></div>', esc_html( sprintf( 'Removed %d orphaned row(s).', $deleted ) ) );
        }

        echo '<div class="wrap"><h1>Orphaned Metadata</h1><table class="widefat striped" style="max-width:520px"><thead><tr><th>Type</th><th>Orphaned rows</th></tr></thead><tbody>';
        $any = 0;
        foreach ( $tables as $label => list( $meta, $fk, $parent, $pk ) ) {
            $count = (int) $wpdb->get_var( "SELECT COUNT(*) FROM $meta m LEFT JOIN $parent p ON p.$pk = m.$fk WHERE p.$pk IS NULL" );
            $any  += $count;
            printf( '<tr><td>%s</td><td>%s</td></tr>', esc_html( $label ), esc_html( number_format_i18n( $count ) ) );
        }
        echo '</tbody></table><form method="post" onsubmit="return confirm(\'Delete all orphaned metadata rows?\');">';
        wp_nonce_field( 'wpide_clean_orphans' );
        submit_button( 'Delete orphaned rows', 'primary', 'wpide_clean_orphans', true, $any ? array() : array( 'disabled' => 'disabled' ) );
        echo '</form></div>';
    } );
} );
```

## Notes

Leftover rows usually come from deleted plugins or direct database edits; take a backup before deleting.

## How to use it

Install the free WPIDE plugin (https://wordpress.org/plugins/wpide/), find "Orphaned Metadata Cleanup Tool" 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/
