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.

I was wondering if anyone could give me some suggestions on how best I could streamline the following;

I have a WordPress blog (privately hosted) which I update daily (well, I normally schedule a load of updates at once) with pictures which I upload, tag and write a very brief comment on.

I was originally considering a folder on the server I could FTP images into and then I would write something that would look there daily and create a post based on the picture, but then I wasn't sure about the meta data that I want along with it.

Any help would be greatly appreciated.

P.S I would make this a community wiki (as I am not sure there is even one answer let alone one stand out correct answer!) but I don't have enough the right privileges yet!

share|improve this question
    
I am not sure how you want to automate it. It is relatively easy to create posts by code, but you will still need to tag and describe by hand - so workflow stays almost same?.. It seems like lots of code (creating posts, scheduling them, keeping track of duplicates, etc) for little gain. –  Rarst Oct 12 '10 at 20:10
    
I was thinking of perhaps tagging the image file itself like img1~funny~dog~.jpg (so funny and dog become tags) and then manually writing the post should it require some extra text. –  Toby Oct 12 '10 at 20:15

2 Answers 2

up vote 10 down vote accepted

Hi @Toby:

There are lots of ways to accomplish a daily picture blog so I'll just give you how I'd approach it.

If I wanted to set up a photoblog on WordPress I'd start with a Flickr account and leverage it (or if you don't like Flickr for some reason you can also look at PhotoBucket, SmugMug, Picasa or one of the other Flickr alternatives.)

Using Flickr

With Flickr there are bulk uploading tools to make it easy for your to upload lots of photos including lots of tools for managing a large number of photos.

Flickr itself has built-in tools to support photo-blogging including email-to-blog.

And if the existing tools don't give you enough control with Flickr you can always write some PHP scripts to integrate and automate. There are lots of blog posts to show you how (and I'll show you how to write one as well, below):

And at least a few PHP libraries to simplify access to the Flickr API:

Exploring the Flickr API

So let's say you want to do a little simple photo blogging to WordPress using files that have been uploaded to Flickr? The first step is to get an API Key:

While you are at it you might want to just scan the API docs:

Now there are a bunch of different ways to query Flickr via their API. I'll show how by Querying a Photo Set but you could also consider Searching by Tags.

For the first example I'll use my Flickr photo set entitled "Barber Motorcycle Museum - Oct 21-22 2006" (I'm using it because people seem to like it; it gets lots of traffic.) You'll need to get the photoset_id which you can find in the URL:

Where to find 'photoset_id' on a Flickr Photo Setlink text

Next you need to call the flickr.photosets.getPhotos method of the Flickr API with a URL of the following format:

http://api.flickr.com/services/rest/?method=flickr.photosets.getPhotos&api_key={YOUR_API_KEY_GOES_HERE}&photoset_id=72157594340403773&media=photos&format=json&nojsoncallback=1

Note that once you replace {YOUR_API_KEY_GOES_HERE} with your own API key you can actually call it from your browser and it will look something like this:

Calling the Flickr API directly from your Browser

Also note that I request JSON back using the format=json&nojsoncallback=1 URL parameters because I find it much easier to handle JSON than XML, and the nojsoncallback omits the callback on would need if working in Javascript.

What you'll get back is a nested data structure containing a list of photos, and for each photos you'll get an object with the following attributes (what I'm showing below it the output of the first element of the array of photos as generated by the standard PHP print_r() function):

[0] => stdClass Object
  (
    [id] => 276672853
    [secret] => 099eaa1af2
    [server] => 107
    [farm] => 1
    [title] => Barber Motorcycle Museum - Oct 22 2006 (500)
    [isprimary] => 0
  )

Flickr's Photo URL Formats

Now that we have our list of recent photos you next need to understand Flickr's Photo URL format which you can read more about here:

In general Flickr's photo URLs go like this:

500px Wide or High "Standard" Photo:

  • http://farm{farm-id}.static.flickr.com/{server-id}/{id}_{secret}.jpg

This version will be 500 pixels on its longest side.

The Original Image:

  • http://farm{farm-id}.static.flickr.com/{server-id}/{id}_{o-secret}_o.(jpg|gif|png)

This can be whatever was uploaded, a .JPG, a .GIF or a .PNG.

Specific Sized Versions:

These are always .JPG:

  • http://farm{farm-id}.static.flickr.com/{server-id}/{id}_{secret}_[size].jpg

Where [size] is one of:

  • s - small square 75x75
  • t - thumbnail, 100 on its longest side
  • m - small, 240 on its longest side
  • z - medium, 640 on its longest side
  • b - large, 1024 on its longest side (only exists for very large original images)

So the following URL taken from the example results returned above pulls the photo that follows (note how the z before the .jpg indicates a photo 640 pixels wide on the longest size:)

Photo of Motorcycle on Flickr

Armed with all of the above information we can now create a PHP script using WordPress' WP_Http class to retrieve the photos from our set. I wrote a simple script which you can copy into the root of your website being sure to replace with your own api_key and photoset_id before running it:

include "wp-load.php";
define('FLICKR_API_KEY','{YOUR_API_KEY_GOES_HERE}');
define('FLICKR_GET_URL','http://api.flickr.com/services/rest/');
define('PHOTO_SIZE_CHAR', 's'); // s = 75x75 pixels on longest side
$result = flickr_get(array(
  'method'      => 'flickr.photosets.getPhotos',
  'photoset_id' => '{YOUR_PHOTOSET_ID_GOES_HERE}',
  'media'       => 'photos'
));
if (isset($result['body']->photoset->photo)) {
  $size = PHOTO_SIZE_CHAR;
  foreach($result['body']->photoset->photo as $photo) {
    extract((array)$photo);
    $url = "http://farm{$farm}.static.flickr.com/{$server}/{$id}_{$secret}_{$size}.jpg";
    echo "<img src=\"{$url}\" alt=\"{$title}\" />\n";
  }
}
function flickr_get($params,$args=array()) {
  $http = new WP_Http();
  $params['api_key'] = FLICKR_API_KEY;
  $params['format'] = 'json';
  $params['nojsoncallback'] = 1;
  $params = http_build_query($params);
  $url = FLICKR_GET_URL . "?{$params}";
  $result = $http->get($url,$args);
  if (isset($result['response']['code']) && $result['response']['code'] == 200)
    $result['body'] = json_decode($result['body']);
  else
    $result = false;
  return $result;
}

Using the above with my API key and my Photoset ID I get the following:

Output of a PHP Script Showing a Flickr Photoset

PHP Script for Posting of a Flickr Photoset Photo to your Blog

Based on all that I've written a page called blog-from-flickr.php that you can put in the root of your website and call to get the following simple form:

Blog From Flickr PHP Script for WordPress

Enter a valid Photoset ID and then click that button and you'll get be redirected to a blog post that looks something like this!

Blog Post Generated from a Flickr Photoset Photo via a PHP Script

To get it all working was a bit more involved than the simple code above and more than I have time left to fully document but I'll post it below for your review (and you can also download it from here).

Of special note are the following aspects in the code:

  • The script pulls the twenty five (25) most recent photos from the photoset and blog the earliest one of those. I assumed you'd want to upload in bulk and then post chronologically. If you upload more than 25 then you need to change the value of the constant FLICKR_PHOTO_COUNT to something larger, up to 500 (500 is the limit specified by Flickr.) Increasing it will only slightly increase how long it takes the script to run; it might not even be noticeable.

  • The script stores Flickr's photo ID as a hidden custom field in wp_postmeta using the key '_flickr_photo_id'. That's how I can tell if it's been blogged before or not.

  • The script uses an HTTP POST method (i.e. using an HTML <form>) vs an HTTP GET method (calling a URL directly) to avoid accidentally triggering the posting process and to allow posting from a different Photoset.

  • The script uses current_user_can('publish_posts') to ensure only a logged-in user with posting rights can trigger the posting logic.

  • The script grabs the photo's description from Flickr and use it as a prefix to the <img> tag for the post content (note my example screenshot didn't have a description hence you see only the photo.)

  • The script calls PHP's getimagesize() with a URL of the photo to get the height and width for the <img> tag; if your server is not configured for that you won't get size and width tags on your images (actually the code might crash; mine works so I couldn't test. If it crashes, you'll know. :)

  • I didn't go to the effort to bring the tags over from Flickr and add them as tags, but that would be a worthwhile exercise for someone else.

And that's about it. On to the code...

The Flickr Photo Blogging Code:

<?php
/*

  blog-from-flickr.php

  Allows the WordPress blog owner to blog a recent photo from a Flickr Photoset just by clicking a button.

  Author: Mike Schinkel (http://mikeschinkel.com)

  Just drop this example into the root of your website and call directly to see it work.
  Use the class in your plugins or themes.

  In Answer To: http://wordpress.stackexchange.com/questions/2830/

*/

include "wp-load.php";
define('FLICKR_API_KEY','{YOUR_FLICKR_API_KEY_GOES_HERE}');
define('DEFAULT_PHOTOSET_ID','{YOUR DEFAULT_PHOTOSET_GOES_HERE');
define('FLICKR_PHOTO_COUNT',25);

define('FLICKR_GET_URL','http://api.flickr.com/services/rest/');

$photoset_id = DEFAULT_PHOTOSET_ID;

if (count($_POST)==0)
  echo <<<HTML
<html>
<body>
  <form method="post">
    Enter Flickr Photoset ID: <input type="text" name="photoset_id" value="{$photoset_id}" size="25" />
    &nbsp;<input type="submit" value="Blog Recent Photo from Flickr!" />
    <input type="hidden" name="go" value="go!" />
  </form>
</body>
</html>
HTML;
else
  BlogFlickrPhotoSetPhoto::blog_photoset_photo($_POST['photoset_id']);

class BlogFlickrPhotoSetPhoto {
  static function blog_photoset_photo($photoset_id) {
    if (current_user_can('publish_posts')) {
      $photoset = self::get_photoset_photos($photoset_id);
      if (!$photoset) {
        echo 'Not a valid Photoset ID. <a href="#">Try again</a>.';
      } else {
        $photo = self::get_photo_to_blog($photoset);
        if (!$photo) {
          echo 'Unexpected Error. Photo Retrieval Failed.';
        } else {
          $permalink = self::blog_photo($photo);
          wp_safe_redirect($permalink);
        }
      }
    }
  }
  static function blog_photo($photo) {
    $img = self::get_photo_html($photo);
    $photo_info = self::get_photo_info($photo->id);
    $description = ($photo_info ? "{$photo_info['body']->photo->description->_content}<br/>" : '');
    $url = self::get_photo_url($photo);
    $post_id = wp_insert_post(array(
      'post_title' => $photo->title,
      'post_type' => 'post',
      'post_author' => 1,
      'post_content' => "{$description}{$img}",
      'post_status' => 'publish',
      'comment_status' => 'open',
      'ping_status' => 'open',
      'post_parent' => 0,
    ));
    if ($post_id) {
      update_post_meta($post_id,'_flickr_photo_id',$photo->id);
      $url = get_permalink($post_id);
    } else {
    $url = false;
    }
    return $url;
  }
  static function get_photo_to_blog($photoset) {
    global $wpdb;
    $photo = false;
    if (isset($photoset['body']->photoset->photo)) {

      //Collect the list of Flickr Photo_ids from our "N" most resent photoset photos
      $photos = $photoset['body']->photoset->photo;
      foreach($photos as $index => $photo) {
        $photo_ids[$index] = $photo->id;
      }
      $photo_id_list = "'" . implode("','",$photo_ids) . "'";

      //Get a list of all photos we've already blogged
      $posts = $wpdb->get_results("SELECT post_id,meta_value FROM wp_postmeta WHERE meta_key='_flickr_photo_id' && meta_value IN ({$photo_id_list})");

      //Remove any photos from the list we've already blogged
      $photo_ids = array_flip($photo_ids);
      foreach($posts as $post) {
        if (isset($photo_ids[$post->meta_value])) {
          unset($photo_ids[$post->meta_value]);
        }
      }

      //Grab the earliest photo we've not blogged
      if (count($photo_ids)==0) {
        $photo = false;
      } else {
        krsort($photo_ids);
        $photo = $photos[reset($photo_ids)];
      }
    }
    return $photo;
  }
  static function get_photoset_photos($photoset_id) {
    $photoset = self::flickr_get(array(
      'method'      => 'flickr.photosets.getPhotos',
      'photoset_id' => $photoset_id,
      'media'       => 'photos',
      'per_page'    => FLICKR_PHOTO_COUNT,
    ));
    return $photoset;
  }
  static function get_photo_info($photo_id) {
    $photo_info = self::flickr_get(array(
      'method'   => 'flickr.photos.getInfo',
      'photo_id' => $photo_id,
    ));
    return $photo_info;
  }
  static function get_photo_html($photo,$size='') {
    $url = self::get_photo_url($photo,$size);
    list($width, $height) = getimagesize($url);
    $hwstring = image_hwstring($width, $height);
    return "<img src=\"{$url}\" alt=\"{$title}\" {$hwstring} />\n";
  }
  static function get_photo_url($photo,$size='') {
    extract((array)$photo);
    $size = (!empty($size) ? "_{$size}" : ''); // If empty the 500px version will be returned.
    return "http://farm{$farm}.static.flickr.com/{$server}/{$id}_{$secret}{$size}.jpg";
  }
  static function flickr_get($params,$args=array()) {
    $http = new WP_Http();
    $params['api_key'] = FLICKR_API_KEY;
    $params['format'] = 'json';
    $params['nojsoncallback'] = 1;
    $params = http_build_query($params);
    $url = FLICKR_GET_URL . "?{$params}";
    $result = $http->get($url,$args);
    if (isset($result['response']['code']) && $result['response']['code'] == 200)
      $result['body'] = json_decode($result['body']);
    else
      $result = false;
    return $result;
  }
}

Fully Automatic Flickr Photo Blogging

If you need to go even farther, you can recode the above to use a pseudo-cron instead of triggering on an HTTP POST. Here's a link to a few articles that can help with that:

And if pseudo-cron isn't good enough, you can alway rename the script to an obscure name and use real cron to retrieve that obscurely-named URL. If you need to go that route, check Google to learn how to set up a cron task..

In either case with cron you'll probably have to remove the current_user_can() code because you won't be logged in.

-Mike

P.S. Getting your Flickr NSID (User ID)

Beyond the above you may find you need to get your Flickr NSID (aka your user ID) for some of the methods, you can find it here:

P.P.S. Authenticating a PHP Script with Flickr is Harder

You may note that none of my examples used required the caller to be authenticated. It's a good bit more involved to authenticate so if you need that be sure to look into the Flickr PHP libraries mentioned as I think they handle that.

share|improve this answer
    
Flickr is def the way to go. –  Joel Glovier Oct 14 '10 at 3:57
    
Thanks @JAG2007! –  MikeSchinkel Oct 14 '10 at 5:45
    
That is perfect, thank you, and thanks for the insanely complete answer. –  Toby Oct 14 '10 at 8:10
    
@Toby - You are welcome. I enjoyed writing it. Hope it comes in handy. –  MikeSchinkel Oct 14 '10 at 10:02
    
@MikeSchinkel You're really gunning for an induction into the "Stellar StackExchange Hall of Fame" aren't you? –  EAMann Oct 15 '10 at 1:43

I would actually recommend using the built-in post by email functionality instead. You set up a private email address (mysupersecretaddress12345@mydomain.com) and send both the images and your descriptions to that address. WordPress will then create a new post from your email and automatically attach the image.

This is a bit easier than FTP.

share|improve this answer
    
This is a great option. And considering you can take a picture with your smart phone and e-mail that way as well, you could easily "automate" things for quick posts easily. –  Dillie-O Oct 12 '10 at 20:38
    
@EAMann - Sorry to piggyback this answer's comments but really glad to see your new avatar. I so much enjoy being able to "see" who I'm writing to as we humans are hardwired for recognizing faces (I like this guy's take: hivelogic.com/articles/why-your-avatar-matters). I think I get grumpy interacting with those whose face I can't see. Now I'm just hoping our other two most active non-facers (@Rarst and @NetConstructor) will follow: mikeschinkel.com/websnaps/skitched-20101014-193647.png –  MikeSchinkel Oct 14 '10 at 23:37
    
@MikeSchinkel My previous avatar was a stylized version of an old photo of me a friend took ... I created it before the Gravatar service was widely used and just stuck with it when everything changed over. But it's been a few years since the last photo was taken and I wanted an update. Besides, a B&W sketch of a silhouette isn't as useful as an actual photo. :) –  EAMann Oct 15 '10 at 1:41
    
@EAMann - Yeah, I think stylized avatars are great in the right contexts, but in generally I really appreciate when I can see the face of the person I'm interacting with. I really think it helps build better relationships. I think that's one thing mailing lists really lack. And as much at Jeff and Joel say SE is about answers, I don't think those of us doing lots of answering would get as much value out of our effort without the relationships and (non-point based) reputations we can build. FWIW. –  MikeSchinkel Oct 15 '10 at 4:27
    
built-in post by email functionality in wordpress. Learning so much new stuff today. Thought only posterous does that. –  skillguru Oct 15 '10 at 21:32

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.