Skip to:

Opened 4 months ago

Last modified 12 days ago

#3580 new defect (bug)

delete_orphaned_spam_meta() has a bug that causes it to loop forever whenever it runs

Reported by: terresquall's profile terresquall Owned by:
Milestone: Awaiting Review Priority: high
Severity: major Version: 2.6.9
Component: Extend - Akismet Keywords: has-patch


The delete_orphaned_spam_meta() function inside bbpress/includes/extend/akismet.php will run forever when there are orphaned post meta keys, because the query keeps searching for orphaned post meta keys by batches of 1000 and deleting them. But there is a check to ignore meta keys that do not start with akismet_.

What happens then is that, if you have any orphaned post meta keys that do not start with 'akismet_', the method will run forever until the max_execution_time expires, because the query finds the rows, but is unable to delete it.

I propose to add the 'akismet_' check into the SQL query, like so:

AND m.meta_key LIKE 'akismet\\_%'

And removing the following check:

// Skip if not an Akismet key
if ( 'akismet_' !== substr( $spam_meta->meta_key, 0, 8 ) ) {

This will prevent the function from looping forever.

Also, since this function finds orphaned bbp_ post meta too, we may want to add this so that it finds both orphaned Akismet and BBP post metas:

AND m.meta_key LIKE 'akismet\\_%' OR m.meta_key LIKE '\\_bbp\\_%')

Here is the final edited code:

public function delete_orphaned_spam_meta() {
        global $wpdb;

        // Get the deletion limit
        $delete_limit = $this->get_delete_limit( '_bbp_akismet_delete_spam_orphaned_limit' );

        // Default last meta ID
        $last_meta_id = 0;

        // Start time (float)
        $start_time = isset( $_SERVER['REQUEST_TIME_FLOAT'] )
                ? (float) $_SERVER['REQUEST_TIME_FLOAT']
                : microtime( true );

        // Maximum time
        $max_exec_time = (float) max( ini_get( 'max_execution_time' ) - 5, 3 );

        // Setup the query
        $sql = "SELECT m.meta_id, m.post_id, m.meta_key FROM {$wpdb->postmeta} as m LEFT JOIN {$wpdb->posts} as p ON m.post_id = p.ID WHERE p.ID IS NULL AND m.meta_id > %d AND (m.meta_key LIKE 'akismet\\_%' OR m.meta_key LIKE '\\_bbp\\_%' ORDER BY m.meta_id LIMIT %d";

        // Query loop of topic & reply IDs
        while ( $spam_meta_results = $wpdb->get_results( $wpdb->prepare( $sql, $last_meta_id, $delete_limit ) ) ) {

                // Exit loop if no spam IDs
                if ( empty( $spam_meta_results ) ) {

                // Reset queries
                $wpdb->queries = array();

                // Reset deleted meta count
                $spam_meta_deleted = array();

                // Loop through each of the metas
                foreach ( $spam_meta_results as $spam_meta ) {

                        // Skip if not an Akismet key
                        __if ( 'akismet_' !== substr( $spam_meta->meta_key, 0, 8 ) ) {

                        // Delete the meta
                        delete_post_meta( $spam_meta->post_id, $spam_meta->meta_key );

                         * Perform a single action on the single topic/reply ID for
                         * simpler batch processing.
                         * @param string The current function.
                         * @param int    The current topic/reply ID.
                        do_action( '_bbp_akismet_batch_delete', __FUNCTION__, $spam_meta );

                        // Stash the meta ID being deleted
                        $spam_meta_deleted[] = $last_meta_id = $spam_meta->meta_id;

                 * Single action that encompasses all topic/reply IDs after the
                 * delete queries have been run.
                 * @param int   Count of spam meta IDs
                 * @param array Array of spam meta IDs
                do_action( '_bbp_akismet_delete_spam_meta_count', count( $spam_meta_deleted ), $spam_meta_deleted );

                // Break if getting close to max_execution_time.
                if ( ( microtime( true ) - $start_time ) > $max_exec_time ) {

        // Maybe optimize

Change History (2)

This ticket was mentioned in PR #14 on bbpress/bbPress by terresquall.

12 days ago

  • Keywords has-patch added; needs-patch removed

#2 @terresquall
12 days ago

I've added a pull request for this.

Note: See TracTickets for help on using tickets.