Recently, one of my clients encountered a significant issue when they lost their entire wp_postmeta
table, and unfortunately, there was no backup available. Our only viable option was to recreate the table and manually add the post meta. However, this posed a new problem. The website has thousands of media files, which became unusable as featured images or anywhere on the site due to their missing metadata. Essentially, the files were present, but WordPress couldn’t utilize them in posts without their associated metadata, a vital piece stored within the wp_postmeta
table.
At first, I considered using a popular plugin made for regenerating thumbnails, assuming it would perform the necessary checks and recreate the missing metadata from the files. However, the plugin failed to regenerate either the metadata or the thumbnails. So, I decided to write a custom code to solve this issue.
The initial part of the code involved hooking a function into wp_head
and checking for a specific query parameter. This approach allowed me to trigger the function by simply adding /?regenerate_attach_meta=1
to the website’s URL. I chose this method because it was a one-time solution, and I planned to remove the code after the metadata was restored.
Here’s the first part of the code:
add_action('wp_head', 'ak_regenerate_attach_meta');
function ak_regenerate_attach_meta()
{
// Check for the presence of the query parameter `regenerate_attach_meta` in the URL
if (!isset($_GET['regenerate_attach_meta'])) {
return;
}
// Implement our code when the `regenerate_attach_meta` query parameter is detected
}
The reason I opted for the wp_head
hook was to facilitate debugging using functions like var_dump
and print_r
with proper styling in place. However, the code can function effectively with other hooks that execute earlier in the process as well.
Moving forward, the next step involved running a meta query to retrieve all the attachments lacking their metadata:
$attachments = get_posts(
array(
'post_type' => 'attachment',
'posts_per_page' => 100,
'fields' => 'ids',
'meta_query' => array(
array(
'key' => '_wp_attachment_metadata',
'compare' => 'NOT EXISTS'
),
),
)
);
It’s worth noting that I set posts_per_page
to 100 to avoid potential timeout errors during script execution. You can adjust this number based on the execution timeout settings on your specific website.
Next step is to make sure certain essential functions are loaded, such as wp_crop_image
and wp_read_video_metadata
, which are usually only available in the wp-admin
section. Here’s how to ensure they’re accessible on the front end:
// Ensure `wp_crop_image` is loaded
if (!function_exists('wp_crop_image')) {
include(ABSPATH . 'wp-admin/includes/image.php');
}
// Ensure `wp_read_video_metadata` is loaded
if (!function_exists('wp_read_video_metadata')) {
include(ABSPATH . 'wp-admin/includes/media.php');
}
Right after that, we loop through the query results and update the attachment metadata using the necessary functions:
// Loop through all attachments with missing metadata
$i = 0;
foreach ($attachments as $attach_id) {
// Check if the attachment has a file meta attached to it
$file = get_attached_file($attach_id);
// If no file is found, generate one and attach it
if (empty($file)) {
$attach_obj = get_post($attach_id);
// Code for generating file path here...
// Update attached file
update_attached_file($attach_id, $filename);
$file = get_attached_file($attach_id);
}
// Generate and update the metadata for the current attachment
if ($file) {
$attach_data = wp_generate_attachment_metadata($attach_id, $file);
wp_update_attachment_metadata($attach_id, $attach_data);
}
// Track the count
$i++;
}
// Display the count of restored attachments
die($i . ' attachment(s) metadata restored');
And that’s it! If you put everything together and open your website with ?regenerate_attach_meta=1
added to the URL, the missing metadata should be recreated for the attachments retrieved by our query. Be sure to run this as many times as needed until all the missing data is fully restored.
To sum it up, here’s the complete snippet:
/**
* Restore/regenerate missing attachment metadata in WordPress.
* Add this to your child theme's functions.php and open you website
* with ?regenerate_attach_meta; ex: example.com/?regenerate_attach_meta=1
*/
add_action('wp_head', 'ak_regenerate_attach_meta');
function ak_regenerate_attach_meta()
{
// Check whether the query parameter `regenerate_attach_meta` exists in the URL
if (!isset($_GET['regenerate_attach_meta'])) {
return;
}
// Run our code if the query parameter `regenerate_attach_meta` was found
$attachments = get_posts(
array(
'post_type' => 'attachment',
'posts_per_page' => 100,
'fields' => 'ids',
'meta_query' => array(
array(
'key' => '_wp_attachment_metadata',
'compare' => 'NOT EXISTS'
),
),
),
);
if (!empty($attachments)) {
// Ensure `wp_crop_image` is loaded
if (!function_exists('wp_crop_image')) {
include(ABSPATH . 'wp-admin/includes/image.php');
}
// Ensure `wp_read_video_metadata` is loaded
if (!function_exists('wp_read_video_metadata')) {
include(ABSPATH . 'wp-admin/includes/media.php');
}
// Loop through all the attachments with missing metadata
$i = 0;
foreach ($attachments as $attach_id) {
// Check if the attachment has a file meta attached to it
$file = get_attached_file($attach_id);
// If no files was found, generate one and attach it
if (empty($file)) {
$attach_obj = get_post($attach_id);
$filename = str_replace(site_url('/wp-content/uploads/', 'https'), '', $attach_obj->guid);
$filename = str_replace(site_url('/wp-content/uploads/', 'http'), '', $filename);
$filename = str_replace(site_url('/', 'https'), '', $filename);
$filename = str_replace(site_url('/', 'http'), '', $filename);
update_attached_file($attach_id, $filename);
$file = get_attached_file($attach_id);
}
// Now generate the metadata and update it for the current attachment
if ($file) {
$attach_data = wp_generate_attachment_metadata($attach_id, $file);
wp_update_attachment_metadata($attach_id, $attach_data);
}
// Save count
$i++;
}
die($i . ' attachment(s) metadata restored');
}
// Show a custom message if all attachments have their metadata in the `wp_postmeta` table
die('No missing metadata');
}
With this snippet, you won’t need to use any plugins to recover your attachment metadata in WordPress.