suppress_errors( true ); $last_error = $wpdb->last_error; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- transaction control, not a data query. $started = $wpdb->query( 'START TRANSACTION READ ONLY' ); $failed = ( false === $started ) || '' !== (string) $wpdb->last_error; // Never leave our own probe in $wpdb->last_error: the caller reports that field to the user // when the real query fails, and a stale transaction error there would be reported as the // reason the query failed. $wpdb->last_error = $last_error; $wpdb->suppress_errors( $suppressed ); if ( $failed ) { return static function (): void {}; } return static function () use ( $wpdb, $last_error ): void { $suppressed = $wpdb->suppress_errors( true ); // COMMIT, not ROLLBACK: nothing was written, so either ends the transaction, and COMMIT // does not look like an error in a slow query log. // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- transaction control. $wpdb->query( 'COMMIT' ); $wpdb->last_error = $last_error; $wpdb->suppress_errors( $suppressed ); }; } }