Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

An existing website have many images placed within the content of pages. I'd like to redesign the template, separating the display of text and images. How could i do that?

share|improve this question
add comment

4 Answers

up vote 4 down vote accepted

You could use, for example, the_content filter, run a regex to remove the images and grab them in a variable, then print that variable wherever you want.

For example, appending all images to the end of the content:

add_filter( 'the_content', 'my_the_content_filter' );
function my_the_content_filter($content) {

  //$matches will be an array with all images
  preg_match_all("/<img[^>]+\>/i", $content, $matches);

  //remove all images form content
  $content = preg_replace("/<img[^>]+\>/i", "", $content);

  //append the images to the end of the content
  foreach($matches as $img) {
       $content .= $img;
  }

  return $content;

}

As suggested by @G.M., you can separate the remove and display of the img.

Define a function to remove the images:

function remove_img_from_content($content) {

  //remove all images form content
  $content = preg_replace("/<img[^>]+\>/i", "", $content);

  return $content;

}

Define a function to get the images:

function get_the_images($content) {

     //$matches will be an array with all images
     preg_match_all("/<img[^>]+\>/i", $content, $matches);
     return $matches;

}

Now wherever you want to display the images you can call the above function passing the content where you want to extract the images from. For example, if you are inside the loop:

//get the content of the current post inside the loop
$content = get_the_content();

//print the text without images:
echo remove_img_from_content($content);

//get the images and print them
$images = get_the_images($content);
foreach($images as $image) {
    echo $image;
}
share|improve this answer
2  
+1. I've just fixed 2 typo. To better answer I'd used a function to be used as template tag, because OP want put images somewhere else than in the content. –  G. M. Sep 17 '13 at 11:05
add comment

I would say if this would be a static page then do not separate it out in a template, use the wp editor to write the html and style it separately. but if it would be a dynamic page it would be great if you make a page template for the same.

if you plan to go with the page template following links might help --

http://codex.wordpress.org/Page_Templates

http://www.expand2web.com/blog/custom-page-template-wordpress/

share|improve this answer
add comment

@cybnet answer is a good one (I've upvoted it) and it's simpler than mine.

When he edit his answer adding feature similar to template tag I had already written the mine.. I decided to don't delete this answer because I use a different approach.

(Explaination after code an in inline comments)

add_action('pre_post_update', 'separate_content_images', 99, 2)
add_filter( 'the_content', 'separate_content_images', 99, 1 );

function separate_content_images( $content = '', $data = -1, $return_img = false ) {

  if ( empty($content) || is_object($content) ) { // function called directly inside loop
    if ( empty($content) ) global $post;
    if ( object($content) ) $post = $content;
    $content = is_object($post) && isset($post->post_content) ? $post->post_content : false;
  }

  if ( ! $content ) return;

  if ( is_int($content) && is_array($data) ) { // function triggered on post update
    $update = $content;
    $content = $data['post_content'];
  }

  $imgs = preg_match_all("/<img[^>]+\>/i", $content, $matches);

  // no images, return content when not in update, null otherwise
  if ( empty($matches) ) return $update ? null : $content;

  $post_images = array();

  foreach ($matches as $img_match ) {
    // save an array of all images in content
    $post_images[] = $img_match[0];
    // remove images from content
    $content = str_replace($img_match[0], '', $content); 
  }

  if ( $update ) {
    // update the post content preventing infinite loop by removing action
    remove_action('pre_post_update', 'separate_content_images', 99, 2);
    wp_update_post( array('ID'=> $update, 'post_content'=> $content) );
    add_action('pre_post_update', 'separate_content_images', 99, 2)
    // save all images in a custom field
    update_post_meta($update , '_post_images', $post_images);
  } else {
    return $return_img ? $post_images : $content;
  }

}

This function is hooked in a pre-update action and in the content filter.

So when a post containing images is updated, the images are stripped out from content and automatically putted in a custom field. The content is also updated to cntain no images.

If a post containing images is shown using the_content, what is printed is the content without images.

But how to print images that are stripped out? write a custom template tag for the purpose:

print_post_images( $args = array(), $post = null ) {

  $defaults = array(
    'wrap' => 'div',
    'wrap_class' => '',
    'before' => '',
    'after' => '<br />',
    'link_to' => 'self' // self img link to file, 'post' to post, other values no link,
    'before_link' => '',
    'after_link' => '',
    'a_class' => '',
    'target' => '',
    'echo' => true
  );

  if ( empty($post) ) global $post;
  if ( is_int($post) ) $post = get_post($post);
  if ( empty($post) || ! isset($post->post_content) ) return;

  $args = extract( wp_parse_args($args, $defaults) );

  // try to get images from custom field (for updated posts)
  $images = get_post_meta($post->ID, '_post_images', true);

  if ( empty($images) ) { // no images in custom field, try on content
    $images = separate_content_images( $post, -1, true );
  }

  if ( ! empty($images) ) {
    $out = '';
    if ($wrap) {
      $format = $wrap_class ? '<%s class="%s">' : '<%s>';
      $out .= sprintf($format, $wrap, esc_attr($wrap_class) );
    }
    foreach ( $images as $image ) {
      if ($link_to == 'post' || $link_to == 'self' ) {
        $format = $a_class ? '<a href="%s" class="%s">' : '<a href="%s">';
        if ( $target ) $format = str_replace('>', ' target="%s">', $format);
        if ($link_to == 'post') {
           $url = get_permalink($post);
        } else {
           preg_match('/src=["']([^"']+)["']/', $image, $matches);
           $url = isset($matches[1]) ? $matches[1] : false;
        } 
        if ( ! $url ) continue;
        if ($before_link) $out .= $before_link;
        $out .= sprintf($format, esc_url($url), esc_attr($a_class), esc_attr($target) );
      }
      if ($before) $out .= $before;
      $out .= $image;
      if ($after) $out .= $after;
      if ($link_to == 'post' || $link_to == 'self' ) {
        $out .= '</a>';
        if ($after_link) $out .= $after_link;
      }
    }
    if ($wrap) $out .= sprintf("</%s>", $wrap);

    // enable a filter to customize the output
    $out = apply_filters('print_post_images', $out, $post, $args);   

    if ($echo) echo $out; else return $out;
  }

}

Now, in your loop, where ever you want, add

<?php print_post_images(); ?>

to print all the images. You can customize a lot the output using provided args. In addition you can customize the output using the custom filter 'print_post_images'.

This function can be used outside the loop using passing post ID or post object as second argument:

<?php print_post_images( $args, $post ); ?>

If you want just return an array of the images, use

<?php $images = separate_content_images( $post, -1, true ); ?>

Where $post can be either a post ID or a post object.

share|improve this answer
add comment

thanks a lot for your answers here is how i have had sorted it:

<?php 
        //get content from back office , filter imgs except featured img to place them later in  <div id='img_content_right'>
                $content2 = get_the_content();                    
                $removed_imgs = array();                 
                $content2 = preg_replace_callback('#(?!<img.+?id="featured_img".*?\/>)(<img.+? />)#',function($r) {
                    global $removed_imgs;
                    $removed_imgs[] = $r[1];
                    return '';
                },$content2);

                    //add filter to the_content to strip images except img_menu et featured_img          
                    add_filter('the_content', 'strip_images',2);                    
                    function strip_images($content){            
                        $content=preg_replace('/(?!<img.+?id="img_menu".*?\/>)(?!<img.+?id="featured_img".*?\/>)<img.+?\/>/','',$content);                                  
                        return $content;                            
                    }

          the_content(); 
?>


  <div id='img_content_right'>
    <?php       
    //append the images stripped from content
     foreach($removed_imgs as $img){
                echo $img;
             }  
    ?>
</div>
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.