Programmatically Set First Image as Featured

I have over 400 posts with images inside them, I have got a new template which requires a featured image for each post, something my last template did not require… I am wondering if there is a script I can add to my functions.php to be able to grab the first image in each post and set it as the featured… So far i have found this, but it is not working…

function auto_set_featured() {
global $post;
$has_thumb = has_post_thumbnail($post->ID);
if (!$has_thumb)  {
$attached_image = get_children( "post_parent=$post->ID&post_type=attachment&post_mime_type=image&numberposts=1" );
    if ($attached_image) {
        foreach ($attached_image as $attachment_id => $attachment) {
            set_post_thumbnail($post->ID, $attachment_id);
        }
    }
}
}
add_action('the_post', 'auto_set_featured');
add_action('save_post', 'auto_set_featured');
add_action('draft_to_publish', 'auto_set_featured');
add_action('new_to_publish', 'auto_set_featured');
add_action('pending_to_publish', 'auto_set_featured');
add_action('future_to_publish', 'auto_set_featured');

This script will work for new posts, but i need it to affect all my older posts, any suggestions?

Related posts

5 comments

  1. Regarding the code you posted, I would say some things:

    • you can avoid using 6 different actions because one is enough: 'save_post' is triggered everytime a post is created or updated
    • you can drop globalize $post: 'save_post' will pass the post id, you can use it, in addition, preparing the function to receive an argument will help you to run the same function programmatically

    The edited version of your code becomes:

    function auto_set_featured( $post = NULL ) {
      // retrieve post object
      $post = get_post( $post ); 
      // nothing to do if no post, or post already has thumbnail
      if ( ! $post instanceof WP_Post || has_post_thumbnail( $post->ID ) )
         return;
      // prepare $thumbnail var
      $thumbnail = NULL;
      // retrieve all the images uploaded to the post
      $images    = get_posts( array(
        'post_parent'    => $post->ID,
        'post_type'      => 'attachment',
        'post_status'    => 'inherit',
        'post_mime_type' => 'image',
        'posts_per_page' => 1
      ) );
      // if we got some images, save the first in $thumbnail var
      if ( is_array( $images ) && ! empty( $images ) )
         $thumbnail = reset( $images );
      // if $thumbnail var is valid, set as featured for the post
      if ( $thumbnail instanceof WP_Post )
         set_post_thumbnail( $post->ID, $thumbnail->ID );
    }
    
    add_action( 'save_post', 'auto_set_featured' );
    

    Now, the only thing you need for old posts, is to retrieve them with a query and then run the same function for every post.

    Just keep attention to perform the task only once: it’s a very time & resource consuming task, so it should be ran only once, possibly on backend.

    I’ll use a transient for the purpose:

    add_action( 'admin_init', function() {
    
      if ( (int) get_transient(' bulk_auto_set_featured' ) > 0 )
         return;
    
      $posts = get_posts( 'posts_per_page=-1' ) ;
      if ( empty( $posts ) )
        return;
    
      array_walk( $posts, 'auto_set_featured' );
    
      set_transient( 'bulk_auto_set_featured', 1 );
    });
    

    After adding this code to your functions.php or to a plugin, log in the backend, and prepare yourself to wait some seconds before the dashboard appear, but after that all post should have a thumbnail, at least every post that has an image uploaded in it.

    If everything goes as it should you can the remove the last code snippet keeping only the first.

    Note my code require php 5.3+

  2. Use this code in your child themes functions file and them regenerate thumbnails

    function wpsites_auto_set_featured_image() {
          global $post;
          $featured_image_exists = has_post_thumbnail($post->ID);
              if (!$featured_image_exists)  {
              $attached_image = get_children( "post_parent=$post->ID&post_type=attachment&post_mime_type=image&numberposts=1" );
                          if ($attached_image) {
                                foreach ($attached_image as $attachment_id => $attachment) {
                                set_post_thumbnail($post->ID, $attachment_id);
                                }
                           }
                        }
      }
    add_action('the_post', 'wpsites_auto_set_featured_image');
    
  3. Simple Function Code

     //Set First Image as FeaturedImage
    add_action('add_attachment', 'set_first_as_featured');
    add_action('edit_attachment', 'set_first_as_featured');
    function set_first_as_featured($attachment_ID)
      {
       $post_ID = get_post($attachment_ID)->post_parent;
       if (!has_post_thumbnail($post_ID)) {
        set_post_thumbnail($post_ID, $attachment_ID);
      }
    }
    
  4. I have had to develop the same functionality. On my case, I had to set the featured images according one posts category.

    Here you have the code you must insert in a template of your current theme. This template must be called, for example: ‘page-set-images.php’ (if you need it you have more information about how creating pages templates here):

    <?php
    
    /* In the URL of the page 'set-images', put as parameter 'setting = 1' to
       set, as featured image of the posts of the category entered that do not
       have featured image, the first image shown in each post. */
    
    echo 'In the URL of the page put as parameter "setting = 1" to set,
    as a featured image of the posts of the category entered that do not have
    featured image, the first image shown in each post.';
    
    $setting = isset($_GET['setting']) ? $_GET['setting'] : '';
    
    if($setting == 1){
        get_posts_by_category();
    }
    
    
    /**
     * We get all the posts in a category. To enter the category, you have to change 
     * the value of the key 'category-name' by the corresponding slug.
     * 
     * @author Sergio Lovillo
     * @return bool
     */
    
    function get_posts_by_category():bool{
    
        $args = array(
            'posts_per_page' => '-1',
            'category_name' => 'category-slug'
        );
        $posts = get_posts($args);
    
        if(isset($posts) && !empty($posts)){
            get_posts_first_image($posts);
        }
        return true;
    }
    
    
    /**
     * We check if each post in the category entered has a featured image; If the 
     * post doesn't have it, we get the URL of the first image shown in the post.
     * 
     * @author Sergio Lovillo
     * @param array $posts
     * Array containing all posts in the category entered
     * @return bool
     */
    
    function get_posts_first_image(array $posts):bool{
    
        $posts_without_thumbnail = 0;
        $changed_posts_total = 0;
    
        foreach($posts as $post){
    
            $featured_image_exists = has_post_thumbnail($post->ID);
    
            if(isset($featured_image_exists) && empty($featured_image_exists)){
    
                $posts_without_thumbnail++;            
                $doc = new DOMDocument();
                $doc->loadHTML(apply_filters('the_content', $post->post_content));
                $xpath = new DOMXPath($doc);
                $src = $xpath->evaluate("string(//img/@src)");
    
                if(isset($src) && !empty($src)){
                    $res = set_posts_featured_images($src, $post->ID);
                } 
                if($res){
                    $changed_posts_total++;
                }         
            }
        }
        echo '<br />---<br />Total posts: ' . count($posts) . '.<br />Posts without 
        featured image: ' . $posts_without_thumbnail . '.<br />Total modified 
        posts:' . $changed_posts_total . '.';
        return true;   
    }
    
    /**
     * We remove the width and height of the URL of the first image shown in the 
     * post. Then we get the ID of the image based on its URL. Finally, we set the 
     * first image displayed in the post as its featured image, using the post ID 
     * and the image ID.
     * 
     * @author Sergio Lovillo
     * @param string $firs_image_url
     * String that contains the URL of the first image shown in the post.
     * @param int $post_id
     * Post ID.
     * @return bool
     */
    
    function set_posts_featured_images(string $first_image_url, int $post_id):bool{
                
        $first_image_formatted_url = preg_replace('/-d+xd+(?=.[a-z]{3,4}$)/i', '', $first_image_url);
        $first_image_url_id = attachment_url_to_postid($first_image_formatted_url);
        $res = false;
        $featured_image_total = 0;
    
        if(isset($first_image_url_id) && !empty($first_image_url_id)){
            $res = set_post_thumbnail($post_id, $first_image_url_id);
        }
        return $res;
    }
    
    ?>
    

    As well, you will have to publish one page with this slug on my example: ‘set-images’. Once the page is published, you must go to that page on your browser and add as parameter ‘setting=1’. So, on my example it would be: https://domain.com/set-images/?setting=1.

    Also, once executed the script, on the page you will be able to see the total of posts of the category, the total of posts of that category without featured image and the total of modified posts.

Comments are closed.