WordPress Hacking – Hiding Images in a Post

WordPress exposes the filter the_content that allows us to hook into the post’s content and modify it as we please. We can use the add_filter function to add our content filter hook in our plugin. One thing to note is that you specify a priority to the filter and you’ll need to specify a high number so the filter runs as late as possible and filters out images. Here’s the code I used to filter out images from the post’s content:

function hideAllImages($content) {
    global $post;

    $imgfilter = array(
        'order' => 'ASC',
        'post_mime_type' => 'image',
        'post_parent' => $post->ID,
        'post_status' => 'inherit',
        'post_type' => 'attachment',);

    $attachments = get_children( $imgfilter );
    $images = array();

    if ( $attachments ) {
        foreach ( $attachments as $attachment ) {
            $imgUrl = wp_get_attachment_url( $attachment->ID );
            if ( SidebarImage_Widget::filterImageUrl($imgUrl) ) {
                $images[] = str_replace('.jpg', '', $imgUrl);
            }
        }
    }

    $imgPattern = "/<img([^\>]*?)>/i";
    if (preg_match_all($imgPattern, $content, $imgTags)) {
        foreach ($imgTags[0] as $imgTag) {
            $imgSrcPattern = '/src="([^"]*?)"/i';
            if ( preg_match($imgSrcPattern, $imgTag, $imgSources) && 
                 !preg_match('/style="display:none;"/i', $imgTag) ) {
                $isMatch = false;
                foreach ( $images as $img ) {
                    $isMatch = strpos($imgSources[1], $img);
                    if ( $isMatch !== false ) {
                        break;
                    }
                }
                if ( $isMatch !== false ) {
                    $pattern = $imgPattern;
                    $replacement = '<img style="display:none;" class="colorbox-none" $1>';
                    $replacedImgTag = preg_replace($pattern, $replacement, $imgTag);
                    $content = str_replace($imgTag, $replacedImgTag, $content);
                }
            }
        }
    }
    return $content;
}

We first iterate through the children of the post that are of type image to find the attached images. We strip the .jpg part of the image URL out and populate the array of attached image URLs. After that find all occurrences of <img> tags in the content and extract the src attribute. We see if this src is matched by any of the filtered attachmentURLs that we built and if so, we hide this image by specifying style="display:none;".  We do a prefix match on the attachment’s URI without the extension – this is because wordpress will automatically create foo_<height>x<width>.jpg files and use them for improving performance. In addition we add class="colorbox-none" so these images are not picked up by colorbox for its slideshow. We use filterImageUrl to filter out emoticons and nextgen gallery thumbnails out from the attachment list so they’ll not be filtered out by this plugin. Finally, here’s the entire plugin code:

<?php
/*
Plugin Name: Sidebar Image
Plugin URI: http://www.nramkumar.org/tech
Description: Hides images from single posts and shows them in the sidebar
Version: 0.5
Author: Ramkumar Natarajan
Author URI: http://www.nramkumar.org/tech
*/

//error_reporting(E_ALL);
add_action('widgets_init', array('SidebarImage_Widget', 'register'));
add_filter('the_content', array('SidebarImage_Widget', 'hideAllImages'), 10);

class SidebarImage_Widget extends WP_Widget {
    function SidebarImage_Widget() {
        parent::WP_Widget(false, 'Sidebar Image Widget');
    }

    function form($instance) {
    }

    function update($new_instance, $old_instance) {
        return $new_instance;
    }

    function filterImageUrl($imgurl) {
        return 
            (strpos($imgurl, '_thumb.jpg') === false) &&
            (strpos($imgurl, 'Emoticon') === false);
    }

    function widget($args) {
        global $post;

        extract($args);

        if ( is_single() ) {
            echo $before_widget;
            echo $before_title . 'Snapshots' . $after_title;
            $imgfilter = array(
                'order' => 'ASC',
                'post_mime_type' => 'image',
                'post_parent' => $post->ID,
                'post_status' => 'inherit',
                'post_type' => 'attachment',);

            $attachments = get_children( $imgfilter );

            if ( $attachments ) {
                $images = array();
                foreach ( $attachments as $attachment ) {
                    $imgUrl = wp_get_attachment_url( $attachment->ID );
                    if ( SidebarImage_Widget::filterImageUrl($imgUrl) ) {
                        $images[] = $attachment;
                    }
                }

                foreach ( $images as $image ) {
                    $imageSrc = wp_get_attachment_image_src( $image->ID, 'medium' );
                    echo '<a href="' . wp_get_attachment_url( $image->ID ) . '" class="cboxElement">' . 
                         '<img src="' . $imageSrc[0] . '" class="colorbox-' . $post->ID . '"></a>';
                }
            }
            else {
                echo __('No Images', 'text_domain');
            }
            echo $after_widget;
        }
    }

    function hideAllImages($content) {
        global $post;

        $imgfilter = array(
            'order' => 'ASC',
            'post_mime_type' => 'image',
            'post_parent' => $post->ID,
            'post_status' => 'inherit',
            'post_type' => 'attachment',);

        $attachments = get_children( $imgfilter );
        $images = array();

        if ( $attachments ) {
            foreach ( $attachments as $attachment ) {
                $imgUrl = wp_get_attachment_url( $attachment->ID );
                if ( SidebarImage_Widget::filterImageUrl($imgUrl) ) {
                    $images[] = str_replace('.jpg', '', $imgUrl);
                }
            }
        }

        $imgPattern = "/<img([^\>]*?)>/i";
        if (preg_match_all($imgPattern, $content, $imgTags)) {
            foreach ($imgTags[0] as $imgTag) {
                $imgSrcPattern = '/src="([^"]*?)"/i';
                if ( preg_match($imgSrcPattern, $imgTag, $imgSources) && 
                     !preg_match('/style="display:none;"/i', $imgTag) ) {
                    $isMatch = false;
                    foreach ( $images as $img ) {
                        // echo __('Pattern ' . $img, 'text_domain');
                        $isMatch = strpos($imgSources[1], $img);
                        if ( $isMatch !== false ) {
                            break;
                        }
                    }
                    if ( $isMatch !== false ) {
                        $pattern = $imgPattern;
                        $replacement = '<img style="display:none;" class="colorbox-none" $1>';
                        $replacedImgTag = preg_replace($pattern, $replacement, $imgTag);
                        $content = str_replace($imgTag, $replacedImgTag, $content);
                    }
                }
            }
        }
        return $content;
    }

    function register(){
        wp_register_sidebar_widget(
            'Sidebar_Image_Widget', 
            'Sidebar Image Widget', 
            array('SidebarImage_Widget', 'widget'));
    }
}
?>

This is a continuation of the series where I attempt to build a solution to display WordPress posts with attached images such that the post content itself doesn’t show any of the images and the sidebar instead displays the images. In my previous post I described creating a simple WordPress plugin with an empty widget.

Now it is time to make the widget do something interesting. In my case, I wanted the widget to display something only if it was being shown in the context of a single post. That is, if you’re viewing a page of posts in the WordPress site, this sidebar widget should not display anything. A bit of searching in the WordPress Codex lead me to the is_singlefunction which allows us to distinguish between a single post or page and a page of posts.

The next task was to figure out how to extract the images associated with a post. WordPress function get_children allows you to do exactly this. Once we get this list, the widget can then output the appropriate HTML to display the images in the sidebar. Here’s the widget function that extracts all the images from a single post and displays them in the sidebar widget only for single posts:

function widget($args) {
    global $post;

    extract($args);

    if ( is_single() ) {
        echo $before_widget;
        echo $before_title . 'Snapshots' . $after_title;
        $imgfilter = array(
            'order' => 'ASC',
            'post_mime_type' => 'image',
            'post_parent' => $post->ID,
            'post_status' => 'inherit',
            'post_type' => 'attachment',);

        $attachments = get_children( $imgfilter );

        if ( $attachments ) {
            $images = array();
            foreach ( $attachments as $attachment ) {
                $imgUrl = wp_get_attachment_url( $attachment->ID );
                $isMatch = strpos($imgUrl, '_thumb.jpg');
                if ( $isMatch === false ) {
                    $isMatch = strpos($imgUrl, 'Emoticon');
                }
                if ( $isMatch === false ) {
                    $images[] = $attachment;
                }
            }

            foreach ( $images as $image ) {
                $imageSrc = wp_get_attachment_image_src( $image->ID, 'medium' );
                echo '<a href="' . wp_get_attachment_url( $image->ID ) . '" class="cboxElement">' . 
                     '<img src="' . $imageSrc[0] . '" class="colorbox-' . $post->ID . '"></a>';
            }
        }
        else {
            echo __('No Images', 'text_domain');
        }
        echo $after_widget;
    }
}

We first specify a filter for get_children that finds the images attached to the current post (note that the current post is available to us in the global $post). Once we have this set of attachments we loop through it, do a bit of pre-processing on it and obtain an array of URLs that we can use in the <img> tags.

In this case, I wanted to make sure that posts that simply showed a NextGen Gallery are treated specially and the images appear in the body of the post and not in the sidebar. I accomplished this by filtering out any image URL that matches _thumb.jpg. Additionally, Windows Live Writer adds images for any emoticons used in a post. Clearly we shouldn’t be moving these out of the post and into the sidebar. This is accomplished by filtering out any image that has Emoticon in the URL. Note that both these filters are excellent “hacks” but not fool-proof. They work well enough for the problem I was trying to solve and I used them.

Once we have the filtered set of images, we just loop through them and emit the HTML required to get them to show up in the sidebar. Note that anything that you echo in the widget method basically gets displayed in the sidebar that has your widget. The code adds the images (at medium size) as clickable links with the same colorbox CSS class thus essentially converting the pictures in the post to a clickable slideshow with medium size thumbnails shown in the sidebar. We only have one more step left – hide the images in the original post content.

 

To follow-up from my previous post, I had a unique requirement for our personal blog which was to display images attached to a post on the sidebar and not in the post. The first item I needed to figure out was how do I hook into the WordPress system to make changes. WordPress has a well developed Plugin model. Additionally, the Sidebar  is populated by something called Widgets which can be implemented by Plugins. So I figured the first thing was to write a WordPress plugin that implemented a Sidebar widget.

For the purpose of this post, I will assume that you have SSH access to your web host and thus able to add files to the WordPress installation without relying on the web UX.

Creating a WordPress plugin consists of the following steps:

  1. Create a new folder to host your plugin under your WordPress installation’s wp-content/plugins folder. I created a folder called wp-content/plugins/sidebarimagefor my new plugin.
  2. Create a <plugin>.php file to host your plugin code in this folder. I created a file called sidebarimage.php in my wp-content/plugins/sidebarimage folder.
  3. Add a custom comment header to the php file so WordPress will recognize it as a plugin. The empty plugin file looks like this at this point:
<?php
/*
Plugin Name: Sidebar Image
Plugin URI: http://www.nramkumar.org/tech
Description: Hides images from single posts and shows them in the sidebar
Version: 0.5
Author: Ramkumar Natarajan
Author URI: http://www.nramkumar.org/tech
*/
?>

Now that we have an empty plugin, the next step was to create an empty widget. This is very straight-forward as well and covered here:

  1. Create a class that extends WP_Widget
  2. Implement a constructor, form, update and widget methods in the class
  3. Register the widget by calling wp_register_sidebar_widget method

At this point, the plugin php file looks like this:

<?php
/*
Plugin Name: Sidebar Image
Plugin URI: http://www.nramkumar.org/tech
Description: Hides images from single posts and shows them in the sidebar
Version: 0.5
Author: Ramkumar Natarajan
Author URI: http://www.nramkumar.org/tech
*/

error_reporting(E_ALL);
add_action('widgets_init', array('SidebarImage_Widget', 'register'));

class SidebarImage_Widget extends WP_Widget {
    function SidebarImage_Widget() {
        parent::WP_Widget(false, 'Sidebar Image Widget');
    }

    function form($instance) {
    }

    function update($new_instance, $old_instance) {
        return $new_instance;
    }

    function widget($args) {
        extract($args);

        echo $before_widget;
        echo $before_title . 'Snapshots' . $after_title;
        echo $after_widget;
    }

    function register(){
        wp_register_sidebar_widget(
            'Sidebar_Image_Widget', 
            'Sidebar Image Widget', 
            array('SidebarImage_Widget', 'widget'));
    }
}
?>

The error_reporting(E_ALL) is used during development so any PHP errors are reported when you view your site. We register the widgets by hooking into thewidgets_init action and calling the register method in our widget class. The register method itself registers the widget class and its output method widget by callingwp_register_sidebar_widget method.

At this point, we now have our empty plugin and widget. You should now be able to see the new widget in the WordPress dashboard under Appearance/Widgets. If you add this widget to a sidebar that gets displayed by your theme, you should see the widget show up with the title Snapshots. Note that we use $before_widget, $before_title, $after_title and $after_widget to format the widget output as recommended by the WordPress codex.

 

We have a personal blog that I host using wordpress on my domain (just like this one). Posts on the personal blog are made by someone who’s not into technology and isn’t interested in details – they’d much rather prefer something that’s user friendly and just works. The posts are usually made using Windows Live Writer which is an excellent WYSIWYG editor for blog posts.

This particular personal blog is heavy on posts with a lot of pictures. One requirement that came up was the ability to put up a post with a series of pictures that show as smaller pictures in the posts but are clickable and launch a picture viewer that then allows you to cycle through all the pictures. After a bit of searching, I found the excellent jQuery Colorbox plugin which does exactly this. Basically, once you setup the right options in jQuery Colorbox, all the images in a single post will be grouped together and can be launched into a slideshow like UX. You can see examples of it in action here.

Once I set up the

Automate jQuery Colorbox for all images in pages, posts and galleries

option, this just started working and the posts with images now showed these images as a clickable slideshow gallery like you see in the demo link. However, after playing with this, a second requirement was made which was slightly trickier.

We wanted a workflow where posts could be made from Windows Live Writer, posts would have a bunch of images attached to them anywhere in the post. When displaying the post however, all the inline images in the post should be hidden from the post and shown in the sidebar. Basically, post writer wanted to just put up a post with a bunch of attached images that they didn’t want to show as part of the post itself but rather in the sidebar and additionally, post writer wanted to continue to use Windows Live Writer for the workflow and WYSIWYG feature for the rest of the post data.

After looking around for a bit to see if someone else had already done the work, I wasn’t able to find anything suitable. I thought for a bit and decided that whatever jQuery Colorbox was doing could be extended to satisfy this requirement – after all, it was already identifying all the images in a post and changing the CSS behavior. In the next series of posts, I will explain how I went about identifying all the images in a WordPress post and will explain and provide the code for hiding the images in the post and displaying them in the sidebar instead.

By Gowtham Grosz

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s