Extract & Display the REAL first image attached to a post – extend the_post_thumbnail()

I have an interesting problem which I am sure someone here can solve. I have gone through a bunch of different plugins and code snippets in search for the perfect code to extract a primary image to be associated with a post.

If the new WP 3.0 featured image element is used then there is of course no issue but there are a bunch of situations where a post may not have a “featured image” assigned. In these situations if you were to use the standard code of:

Read More
<?php echo the_post_thumbnail( array(200,200) ); ?>

in your template… nothing is going to be displayed.

For these type of situations I am looking for the perfect solution. Essentially, what I need is the ability to have a type of “failover” when the_post_thumbnail does not exist but I also still need the ability to set the image size just like I can with the code from the_post_thumbnail.

This “failover” I believe should have two steps to it:

  1. Check the “Media Gallery” for this post and locate the image with the highest sort order (or added post parent as shown in the plugin below)
  2. If no sort order is set or if blank then extract the first image from the post content.

The good news is that for the two points above I seem to have found two separate snips of code which take care of these requests individually (copied below for review) however nothing which combines all three of these elements in one.

So, to recap:
Instead of doing a bunch of if/then calls to check if a post thumbnail exists and then running a check against the code below I was hoping that someone might be able to provide a clean/combined function which would allow me to echo a single function along with size variables which can achieve all three these goals as mentioned above.

HERE ARE THE BITS OF CODE MENTIONED ABOVE:


FOR #1: Get the First Image based off the order from the Media Gallery:
This code works by first looking for any attachments in the wp_posts database table that have a “post_parent” ID that matches the current post and as a second step for posts with multiple image attachments, returning the attachment with its “menu_order” field set to “1″. If no image attachments match the current post ID, the plugin returns “false”.

// AUTOMATICALLY EXTRACT IMAGES BASED ON ASSOCIATED GALLERY ORDER
// THIS CODE EXTRACTS THE FIRST IMAGE BASED ON THE ORDER IN THE MEDIA GALLERY
// PLUGIN FROM: http://mekosh.org/projects/ordered-thumbnails
   function ordered_thumbnails( $display = 'true', $class='' ) {
    global $post;
    // get all image attachments for this post
    $images = get_children( array( 'post_type' => 'attachment', 'post_parent' => $post->ID, 'post_mime_type' => 'image', order=>"asc" ) );
    // if the post has image attachments
    if( $images !== false ) {
        // find the image in position 1
        foreach($images as $i) {
            if ( $i->menu_order == 1 ) {
                $img_id = $i->ID;
            }
        }
        // if the images were unordered
        if ( $img_id == '' ) {
            $i = array_slice( $images, 0, 1 );
            $img_id = $i[0]->ID;
        }
        // get image data
        $image = wp_get_attachment_image_src( $img_id, 'thumbnail' );
        $result = array(
            'url'       => $image[0],
            'width' => $image[1],
            'height'    => $image[2]
        );
        // should the image be displayed or should data be returned as an array?
        if ( $display == 'true' ) {
            return _e( '<img src="'.$result['url'].'" width="'.$result['width'].'" height="'.$result['height'].'" class="'.$class.'" />' );
        } else {
            return $result;
        }
    } else {
        // post does not have any image attachments
        return (bool) false;
    }
   }
// create template tag "ordered_thumbnails"
   add_action( 'ordered_thumbnails', 'ordered_thumbnails', 2 );

FOR #2: Extract the first image from the post content

// THIS CODE GETS THE FIRST IMAGE EXTRACTED DIRECTLY FROM THE POST CONTENT

    function bm_extract_string($start, $end, $original) {
    $original = stristr($original, $start);
    $trimmed = stristr($original, $end);
    return substr($original, strlen($start), -strlen($trimmed));
    }
    function getFirstImage() {
    $content = get_the_content();
    $pic_string = bm_extract_string('src="','" ',$content);
    $imagesize = getimagesize($pic_string);
    list($width, $height, $type, $attr) = getimagesize($pic_string);
    $link = get_permalink();
    $title = get_the_title($post->post_title);
    echo '<a href="'.$link.'" style="background:url('.$pic_string.'); display:block; width:'.$width.'px; height:'.$height.'px;" title="'.$title.'"></a>';
    }

Related posts

Leave a Reply

4 comments

  1. I suggest to check out Get the Image plugin. Basically it is single function that acts as flexible and configurable wrapper to mine posts for images via different methods (post meta fields, featured images, attached images, images in post body).

  2. Here is the solution to my problem for anyone who is interested.

    Include this in your functions.php file

    require_once('custom/extract-post-thumbnail.php');
        $extract_img = new extract_post_image();
        add_filter( 'post_thumbnail_html', array(&$extract_img, 'get_post_image'),1,5 );
    

    Create a new file and name it “extract-post-thumbnail.php”, place it into a folder named “custom” and place that within the the same directory that your themes functions.php file is located. Finally, past the code below into this file.

    <?php
    class extract_post_image {
        public $html;
        public $post_id;
        public $post_image_id;
        public $size;
        public $attr;
        public function extract_post_image()  {
        }
        public function get_post_image ($html,$post_id, $post_image_id, $size, $attr) {
    $this->html = $html;
            $this->post_id = $post_id;
            $this->post_image_id = $post_image_id;
            $this->size = $size;
            $this->attr = $attr;
        if ($this->html == '') {
             $this->post_image_id = $this->get_post_image_id ();
             if ($this->post_image_id) {
               do_action( 'begin_fetch_post_thumbnail_html', $this->post_id, $this->post_image_id, $this->size ); 
            $this->html = wp_get_attachment_image( $this->post_image_id, $this->size, false, $this->attr );
            do_action( 'end_fetch_post_thumbnail_html', $this->post_id, $this->post_image_id, $this->size );
        } else {
            $this->html = $this->get_image_in_content ();
        }
        }
        return $this->html;
    }
    public function get_post_image_id () {
        $images = get_children(
        array(
            'post_parent' => $this->post_id,
            'post_status' => 'inherit',
            'post_type' => 'attachment',
            'post_mime_type' => 'image',
            'order' => 'ASC',
            'orderby' => 'menu_order',
            'numberposts' => 1
            )
        );
        if ($images) {
            foreach ($images as $img) {
            $img_id = $img->ID;
            }
            return $img->ID;
            } else {
               return NULL;
            }
    }
    public function remote_file_exists($image) {
        if ( @file($image)) {
            return true;
        }
        return false;
    }
    public function get_image_in_content () {
        $my_post = get_post($this->post_id);
        preg_match_all( '|<img.*?src=['"](.*?)['"].*?>|i', $my_post->post_content, $matches );
        if ( isset( $matches ) ) {
                $image = $matches[1][0];
        if ( $matches[1][0] && $this->remote_file_exists($image) ) {
                $altpattern = '/alt=(['"])?(.*?)\1/';
                preg_match($altpattern, $matches[0][0], $m);
                $alt = $m[2];
                $default_attr = array(
                'src'   => $image,
                'class' => "attachment-$size",
                'alt'   => $alt
            );
                $this->attr = wp_parse_args($this->attr, $default_attr);
            $attr = array_map( 'esc_attr', $this->attr );
            $attributes = '';
            foreach ( $this->attr as $name => $value ) {
                $attributes .= " $name=" . '"' . $value . '"';
            }
               $imgwh = getimagesize($image);
               $imgsize = image_constrain_size_for_editor($imgwh[0], $imgwh[1], $this->size);
               $wh = image_hwstring($imgsize[0], $imgsize[1]);
               $this->html = ' <img '.$attributes.' '.$wh.' />';
                    return $this->html;
            }
            } else {
            return NULL;
            }
    }
    }
    ?>
    
  3. @NetConstructor,

    This function will not solve all your issues but I thought it would help. It gets the first image attached to a post and adds the medium sized image to the_content If no sort order is set it will get the image with the “0” sort order. It does not extract anything from the post content and if the image is in the post content it will be displayed 2 times.

    I used it for a client who had trouble inserting images in posts. With this function he only has to click the “add media” button, upload the image and click save without having to “insert” it.

    function the_image($size = 'medium' , $class = ”){
    global $post;
    
    //setup the attachment array
    $att_array = array(
    'post_parent' => $post->ID,
    'post_type' => 'attachment',
    'post_mime_type' => 'image',
    'order_by' => 'menu_order'
    );
    
    //get the post attachments
    $attachments = get_children($att_array);
    
    //make sure there are attachments
    if (is_array($attachments)){
    //loop through them
    foreach($attachments as $att){
    //find the one we want based on its characteristics
    if ( $att->menu_order == 0){
    $image_src_array = wp_get_attachment_image_src($att->ID, $size);
    
    //get url – 1 and 2 are the x and y dimensions
    $url = $image_src_array[0];
    $caption = $att->post_excerpt;
    $image_html = '<img src="%s" alt="%s" />';
    
    //combine the data
    $html = sprintf($image_html,$url,$caption,$class);
    
    //echo the result
    echo $html;
    }
    }
    }
    }