Wordpress : excluding images 'inserted into post' from get_children
Asked Answered
B

7

6

I have a page which has a slideshow at the top, and images inserted inline into the content area.

I need to exclude the images that have been inserted into the post from the slideshow.

Currently I am excluding the 'Featured Image', but this limits me to one image that can be inserted into the post.

Here is my existing code:

$thumbnail = get_post_thumbnail_id();
$images = get_children( 'post_type=attachment&post_mime_type=image&order=asc&orderby=menu_order&post_parent='.$post->ID .'&exclude='.$thumbnail);

Previously I have used the description field of the image meta data to exclude images by entering 'exclude'. This isn't as nice for the end user as I'd like it to be.

Any suggestions, plugins or code based!

Update: I've updated the code, so now I get any image URLs from the post_content and check them against the slideshow images.

    $content = $post->post_content;
    $inlineImages = array();
    preg_match( '/src="([^"]*)"/i', $content, $inlineImages ) ;
    $thumbnail = get_post_thumbnail_id($post->ID);

    $images = get_children( 'post_type=attachment&post_mime_type=image&order=asc&orderby=menu_order&post_parent='.$post->ID .'&exclude='.$thumbnail);

    if ($images) {
        echo '<div id="slideshow">';
        foreach ( $images as $attachment_id => $attachment ) {
            $image = wp_get_attachment_image_src( $attachment_id,array(900,265)); 

            if (!in_array($image[0],$inlineImages)) {
                echo '<img src="'.$image[0].'" width="'. $image[1] .'" height="'. $image[2].'">';
            }
        }
        echo '</div>';
    }

This is an OK solution, although the regex could be improved.

A nicer step would be to add the array of images to a custom field field, which is updated on post / page update or publish.

Any suggestions on how to go about this?

Bengal answered 1/1, 2012 at 23:9 Comment(1)
Are you manually attaching slideshow images to the page via the admin media menu?Bust
B
4

I've updated the code, so now I get any image URLs from the post_content and check them against the slideshow images.

$content = $post->post_content;
$inlineImages = array();
preg_match( '/src="([^"]*)"/i', $content, $inlineImages ) ;
$thumbnail = get_post_thumbnail_id($post->ID);

$images = get_children( 'post_type=attachment&post_mime_type=image&order=asc&orderby=menu_order&post_parent='.$post->ID .'&exclude='.$thumbnail);

if ($images) {
    echo '<div id="slideshow">';
    foreach ( $images as $attachment_id => $attachment ) {
        $image = wp_get_attachment_image_src( $attachment_id,array(900,265)); 

        if (!in_array($image[0],$inlineImages)) {
            echo '<img src="'.$image[0].'" width="'. $image[1] .'" height="'. $image[2].'">';
        }
    }
    echo '</div>';
}
Bengal answered 8/1, 2012 at 14:37 Comment(0)
P
6

Just needed to do the same thing. Your original approach is the way I wanted to do it -- simply exclude any images that had been inserted into the post from appearing in the slider. But I didn't want the client to have to do anything special to make it happen. Here's my code.

$args = array( 'post_type' => 'attachment', 'post_mime_type'=>'image','numberposts' => -1, 'post_status' => null, 'post_parent' => $post->ID ); 
$attachments = get_posts($args);
preg_match_all("/<img[^']*?src=\"([^']*?)\"[^']*?>/", $post->post_content, $matches, PREG_PATTERN_ORDER);
/* $matches[1] holds the urls as an array */
foreach ( $attachments as $attachment ) {
if(in_array($attachment->guid, $matches[1])){ continue;}
wp_get_attachment_image( $attachment->ID , 'slider_size'); 
}

First bit gets all of the images associated with the post. The $preg_match_all gets all of the images in the post body. Then as we loop through the images to display them in the slider the in_array checks the urls of the images that were inserted with the url of the image about to be added to the slider and skips on to the next one if there is a match.

Thanks for you post, got me thinking in the right direction.

Privity answered 14/12, 2012 at 23:4 Comment(1)
Nice method! This may only apply to recent WP versions but I find that the $attachment->guid and the value in the $matches Array do not match as the image inserted to the post would have the image size appended to the end of the file name? My quick fix is to select Size full when inserting the image without the additional file size or edit it in the post, both not great solutions .Dameron
B
4

I've updated the code, so now I get any image URLs from the post_content and check them against the slideshow images.

$content = $post->post_content;
$inlineImages = array();
preg_match( '/src="([^"]*)"/i', $content, $inlineImages ) ;
$thumbnail = get_post_thumbnail_id($post->ID);

$images = get_children( 'post_type=attachment&post_mime_type=image&order=asc&orderby=menu_order&post_parent='.$post->ID .'&exclude='.$thumbnail);

if ($images) {
    echo '<div id="slideshow">';
    foreach ( $images as $attachment_id => $attachment ) {
        $image = wp_get_attachment_image_src( $attachment_id,array(900,265)); 

        if (!in_array($image[0],$inlineImages)) {
            echo '<img src="'.$image[0].'" width="'. $image[1] .'" height="'. $image[2].'">';
        }
    }
    echo '</div>';
}
Bengal answered 8/1, 2012 at 14:37 Comment(0)
I
0

I think the easiest thing to do would be using the Meteor Slideshow plugin to create a slideshow for each page, then insert the shortcode for the proper slideshow in the content area of the proper page. Yes, it means you'll have to edit each page "outside" the page editor, but it also gives you easy, complete control over which photos do and do not appear in each slideshow, and the shortcode is very easy to put in with the page editor.

Indomitability answered 10/1, 2012 at 23:42 Comment(0)
B
0

The Media Custom Fields plugin lets you add custom data to media items exactly as you would with custom post fields, providing a user-friendly way of flagging slideshow-only images. From the plugin FAQ:

In addition to giving you the option to add custom fields, your custom fields will show up in all appropriate places. If you go to the media section to manage your media like you usually do, they will show up on the edit media form. The custom fields also show up when you are uploading an image to a post, and in all other expected locations.

One approach is to install this plugin and add a custom field such as Slide with value TRUE to your slide images via the Dashboard -> Media menu. Then your filter code might be:

$thumbnail = get_post_thumbnail_id();
$images = get_children( /* removed for brevity */ );

if ($images) {
    // ..
    foreach ( $images as $attachment_id => $attachment ) {
        // skip images not marked for slideshow
        if ( !get_post_meta($attachment_id, 'Slide') ) continue; 

        // otherwise do slideshow things
    }
    // ..
}

Note that with this approach the value for Slide can be set to anything except the empty string. You may want to define Slide as a class constant somewhere to avoid hard-coding.

Advantages

  1. Doesn't require any work on the poster's part
  2. Future-proof: the plugin appears to be based on good-old post functionality, and attachments are just one kind of post anyway, so there's nothing weird.
Bust answered 11/1, 2012 at 1:53 Comment(0)
R
0

Here is another approach to this.

I would not prefer using urls, because the picture inserted inside the content area could be of different size like medium, thumbnail or full. So, the url only would not match.

Using the above code,

function printMeImages() {

  $content = $post->post_content;
  $inlineImages = array();

  // populate ids of images from wp-image-id
  preg_match_all( '/wp-image-([^"]*)"/i', $content, $inlineImages ) ;

  $thumbnail = get_post_thumbnail_id($post->ID);

  $images = get_children( 'post_type=attachment&post_mime_type=image&order=asc&orderby=menu_order&post_parent='.$post->ID .'&exclude='.$thumbnail);

  $out = "";

  if ($images) {
      $out .= '<ul id="slideshow">';
      foreach ( $images as $attachment_id => $attachment ) {
          $image = wp_get_attachment_image_src( $attachment_id,'desiredImageSize'); 
          // $inlineImages[1] has ids to be discarded
          if (!in_array($attachment_id,$inlineImages[1])) {
              $out .= '<li><img src="'.$image[0].'" width="'. $image[1] .'" height="'. $image[2].'"></li>';
          }
      }
      $out .= '</ul>';
  }

  return $out;

}

The images which are not set as featured and not used inside the post are retrieved.

Rabush answered 17/3, 2013 at 0:12 Comment(1)
This may not work as the images may be uploaded to a different folder depending on your permilink structure.Accompaniment
L
0

For performance reasons I would not execute the code while the page is being rendered, but rather bind the code to the save_post hook. When the post content is edited and saved, the hook will be called and all attached images (or their ids) which are not used in the content are saved into a postmeta table. When the slider is rendered the image ids can be accessed via get_post_meta($post_id, 'image_ids_for_slider'). Like this I can avoid to do the preg_match_all operation on page rendering. This might not be a performance reason when the post content is small and when there's only one slider loaded, but generally I find this a approach a little cleaner for scaling reasons.

//hook this function to save post action
function save_ids_of_image_attachments_not_used_in_the_content( $post_id, $post ) {

    $args = array(  'post_type' => 'attachment', 
                    'post_mime_type'=>'image',
                    'numberposts' => -1, 
                    'post_status' => null, 
                    'post_parent' => $post_id
    ); 
    $attachments = get_posts($args);    
    preg_match_all("/<img[^']*?src=\"([^']*?)\"[^']*?>/", $post->post_content, $matches, PREG_PATTERN_ORDER);

    $ids_of_attached_images_not_in_content = array();

    /* $matches[1] holds the urls as an array */
    foreach ( $attachments as $attachment ) {
        if(in_array($attachment->guid, $matches[1])){ 
            continue;
        }
        $ids_of_attached_images_not_in_content[] = $attachment->ID;
    }

    // save the image_ids as postmeta
    update_post_meta($post_id, 'image_ids_for_slider', $ids_of_attached_images_not_in_content);
}
add_action( 'save_post', 'save_ids_of_image_attachments_not_used_in_the_content', 10, 2 );
Lectionary answered 12/1, 2014 at 19:12 Comment(0)
O
-1

I haven't fully understood your problem, but how about excluding the div ID within which the slideshow is present?

$thumbnail = get_post_thumbnail_id();
$images = get_children('post_type=attachment&post_mime_type=image&order=asc&orderby=menu_order&post_parent='.$post->ID .'&exclude='.$thumbnail. '&NAME');

Replace 'NAME' after thumbnail.' in the parenthesis. Hope this helps.

Orthorhombic answered 4/1, 2012 at 7:28 Comment(1)
That won't work. Get_children has set parameters. Thanks though.Bengal

© 2022 - 2024 — McMap. All rights reserved.