I have around 2,500+ posts on my site where I’ve inserted images using the traditional method into the post content itself.
In upgrading to a different theme, the single post page now displays the featured image as well before the title (which I want to keep), but I now would like to remove the first image from the_content to prevent duplicate images from showing up.
I know that it can be done with this filter, but is there are way to permanently remove the first images from my old posts other than manually going through each one?
function remove_first_image ($content) {
if (!is_page() && !is_feed() && !is_feed() && !is_home()) {
$content = preg_replace("/<img[^>]+\>/i", "", $content, 1);
} return $content;
}
add_filter('the_content', 'remove_first_image');
I feel as if this filter might be resource intensive and be very unflexible for things I might wish to do in future within posts.
Another thread mentioned “Export your database tables to your desktop.than you can remove all unwanted tags by using any text editor such as notepad++.” but I’m not familiar with how to do that.
Any help is appreciated. Thanks
Just as @s_ha_dum suggests, you can loop through all of your posts and update the content of each one.
The following gives you the idea but is untested:
$posts = get_posts( array(
'post_type' => 'post',
'posts_per_page' => 500,
'offset' => 0,
) );
foreach( $posts as $post ):
// Update each post with your reg-ex content filter:
$pid = wp_update_post( array(
'ID' => $post->ID,
'post_content' => preg_replace( "/<img[^>]+\>/i", "", $post->post_content, 1 )
) );
// Show the update process:
printf( '<p>Post with ID: %d was %s updated</p>',
$post->ID,
( 0 < $pid ) ? '' : 'NOT'
);
endforeach;
To avoid PHP timeout, I added a finite number of posts to update with a given offset. You can adjust this to your needs. It’s best to try it first on a single post while you’re testing it.
But remember to backup your database before testing this!
Demo Plugin – First Image Remover
Here’s a demo plugin with a custom admin page:

and it’s own admin menu item:

You can create a plugin file /wp-content/plugins/first-image-remover/first-image-remover.php
with the following code:
<?php
/**
* Plugin Name: First Image Remover
* Description: Remove the first image from the post content
* Plugin URI: http://wordpress.stackexchange.com/a/142494/26350
* Version: 0.0.1
*/
/**
* Create the 'First Image Remover' admin menu
*/
function wpse_142494_create_menu()
{
// Create new top-level menu:
add_menu_page(
'First Image Remover',
'First Image Remover',
'manage_options',
'wpse_142494_settings_page',
'wpse_142494_settings_page'
);
}
add_action('admin_menu', 'wpse_142494_create_menu');
/**
* Create the 'Image Replacer' settings pge
*/
function wpse_142494_settings_page()
{
?>
<div class="wrap">
<h2>First Image Remover</h2>
<p>Remove the first image of each post in the selected loop.</p>
<h3>Help:</h3>
<p>Avialable GET parameters:
<pre>
wpse_ppp - Posts Per Page (int),
wpse_offset - Offset (int),
wpse_update - Update mode (boolean)
Update Example for 5 posts with offset 10:
/wp-admin/admin.php?page=wpse_142494_settings_page&wpse_offset=10&wpse_ppp=5&wpse_update=yes
</pre>
<h3>Loop:</h3>
<?php wpse_142494_loop(); ?>
</div>
<?php
}
/**
* Fetch posts based on user input
*/
function wpse_142494_loop()
{
// Only site admin can update posts:
if( ! current_user_can( 'manage_options' ) ) return;
// Get user input:
$params = filter_input_array( INPUT_GET, array(
'wpse_offset' => FILTER_SANITIZE_NUMBER_INT,
'wpse_ppp' => FILTER_SANITIZE_NUMBER_INT,
'wpse_update' => FILTER_VALIDATE_BOOLEAN,
) );
// Fetch posts to update:
$posts = get_posts( array(
'post_type' => 'post',
'posts_per_page' => ( ! empty( $params['wpse_ppp'] ) ) ? $params['wpse_ppp'] : 10 ,
'offset' => ( ! empty( $params['wpse_offset'] ) ) ? $params['wpse_offset'] : 0,
) );
// Loop through posts:
$li = '';
foreach( $posts as $post ):
if( $params['wpse_update'] ):
// Update each post with your reg-ex content filter:
$pid = wp_update_post( array(
'ID' => $post->ID,
'post_content' => preg_replace( "/<img[^>]+\>/i", "", $post->post_content, 1 )
) );
// Show the update process:
$li .= sprintf( '<li>%d - <strong>%s</strong> - was %s updated</li>',
$post->ID,
$post->post_title,
( 0 < $pid ) ? '' : 'NOT'
);
else:
// Show the post list that will be updated
$li .= sprintf( '<li>%d - <strong>%s</strong> - will be updated</li>',
$post->ID,
$post->post_title
);
endif;
endforeach;
// Output:
printf( '<strong>Settings:</strong> Posts: %d - Offset: %d - Update: %s <ul>%s</ul>',
$params['wpse_ppp'],
$params['wpse_offset'],
$params['wpse_update'] ? 'ON' : 'OFF',
$li
);
}
where you can access it from:
/wp-admin/admin.php?page=wpse_142494_settings_page
You can then adjust it to your needs with the following GET parameters:
/wp-admin/admin.php?page=wpse_142494_settings_page&wpse_offset=10&wpse_ppp=5&wpse_update=no
When you run it in the update mode (wpse_update=yes
) you will get something like:

You can then hopefully extend this and adjust to your needs.