# Find and Remove Orphaned Post Meta (WP-CLI)

> Adds a "wp orphaned-meta" command that counts custom field rows left behind by deleted posts, grouped by meta key, and removes them in small batches when you add --delete.

- Type: PHP
- Runs: Run everywhere
- Category: [Developer](https://wpide.com/library/category/developer/)
- Tags: wp-cli, database, cleanup
- Author: WPIDE Team
- Installs: 0
- Updated: 2026-10-28
- Page: https://wpide.com/library/cli-orphaned-meta-report/

## Code

```php
if ( ! defined( 'WP_CLI' ) || ! WP_CLI ) {
    return;
}

WP_CLI::add_command( 'orphaned-meta', function ( $args, $assoc_args ) {
    global $wpdb;

    $rows = $wpdb->get_results(
        "SELECT pm.meta_key, COUNT(*) AS rows_found FROM {$wpdb->postmeta} pm
        LEFT JOIN {$wpdb->posts} p ON p.ID = pm.post_id
        WHERE p.ID IS NULL GROUP BY pm.meta_key ORDER BY rows_found DESC",
        ARRAY_A
    );

    if ( ! $rows ) {
        WP_CLI::success( 'No orphaned post meta found.' );
        return;
    }

    WP_CLI\Utils\format_items( 'table', $rows, array( 'meta_key', 'rows_found' ) );

    if ( empty( $assoc_args['delete'] ) ) {
        WP_CLI::log( 'Add --delete to remove these rows.' );
        return;
    }

    $deleted = 0;
    do {
        // Batches keep table locks short on big sites.
        $ids = $wpdb->get_col(
            "SELECT pm.meta_id FROM {$wpdb->postmeta} pm LEFT JOIN {$wpdb->posts} p ON p.ID = pm.post_id WHERE p.ID IS NULL LIMIT 1000"
        );
        if ( $ids ) {
            $deleted += (int) $wpdb->query( "DELETE FROM {$wpdb->postmeta} WHERE meta_id IN (" . implode( ',', array_map( 'absint', $ids ) ) . ')' );
        }
    } while ( count( $ids ) === 1000 );

    wp_cache_flush();
    WP_CLI::success( sprintf( 'Deleted %d orphaned meta rows.', $deleted ) );
}, array(
    'shortdesc' => 'Reports or deletes post meta whose post no longer exists.',
    'synopsis'  => array(
        array( 'type' => 'flag', 'name' => 'delete', 'optional' => true ),
    ),
) );
```

## Notes

Back up the database before running with --delete.

## How to use it

Install the free WPIDE plugin (https://wordpress.org/plugins/wpide/), find "Find and Remove Orphaned Post Meta (WP-CLI)" 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/
