Responsive images with srcset in WordPress

As a developer, I am somewhat conservative. I believe strongly in the importance of web standards, and I am reluctant to be an early adopter of any new techniques or, even worse, non-standard workarounds for limitations in existing standards. I’d rather live with the limitations until a proper standard — or at least a de facto standard — takes hold.

One of the latest issues to challenge my approach has been responsive images. I’ve settled into a pattern of going with “1.5x” quality images, trying to strike a balance between quality on large high-res displays and a reasonable file size. But it really doesn’t do either very well.

Today’s issue of A List Apart features an exciting article:

Responsive Images in Practice

Yes! In practice! Let’s do this!

There have been a couple of competing proposals for handling responsive image sets, and I am pleased to see the srcset attribute begin to emerge as the winner. The biggest plus it has for me is that it degrades gracefully for older browsers that don’t support it.

Well, before I had even finished reading the article I started thinking about how I could leverage the build-in image sizing mechanism in WordPress to use srcset. I haven’t looked around — I’m sure someone else has already created a plugin that perfectly nails what I am attempting to do here. And, to be honest, I haven’t extensively tested this code yet, although I did drop it into a site I’m currently working on, just to be sure it doesn’t throw a fatal error and that it actually does render the HTML <img> tag as advertised.

function img_with_srcset($attachment_id, $default_size='medium', $echo=true) {
  $output = null;

  // Get image metadata
  $image = wp_get_attachment_metadata($attachment_id);

  // Set upload directory for image URLs
  $upload_dir = wp_upload_dir();
  $upload_url = $upload_dir['baseurl'] . '/' . dirname($image['file']) . '/';

  // Build array of sizes for srcset attribute
  $sizes = array();
  foreach ($image['sizes'] as $size) {
    $sizes[$size['width']] = $upload_url . $size['file'] . ' ' . $size['width'] . 'w';
  }
  
  // Sort sizes, largest first
  krsort($sizes);

  // Get image alt text
  $image_alt = get_post_meta($attachment_id, '_wp_attachment_image_alt', true);

  // Generate output <img> tag
  if (!empty($sizes)) {
    $output =  '<img srcset="' . implode(', ', $sizes) . '" ' .
               'src="' . $upload_url . $image['sizes'][$default_size]['file'] . '" ' .
               'alt="' . esc_html($image_alt) . '" />';
  }
  
  // Return/echo output
  if ($echo) {
    echo $output;
    return true;
  }
  else {
    return $output;
  }
}

Let’s just examine what’s going on here.

The function takes three input parameters. An attachment ID, a default size (for the old school src attribute), and a boolean for whether to echo the output or just return it.

First, we get the attachment metadata and put it into $image. You can see more about what the wp_get_attachment_metadata() function does here.

Next, we set up the $upload_url variable to be the full base URL to the WordPress uploads directory. That’s because the metadata output only includes the filename of each sized image, not its full URL.

Then we loop through all of the sizes in the metadata output, generating a series of strings containing the image URL and its width, for use in the srcset attribute. We put these into an array because we need to manipulate the list a bit: we need to sort it so the largest images come first, and then later we need to implode() this into a comma-separated string.

Of course we also need the image’s alt text, so we grab that with get_post_meta() which you can read more about here.

Finally, assuming we actually have some size data, we build the <img> tag, complete with srcset attribute! Then we either echo or return it, as determined by the $echo input parameter.

Something else I’d like to try with this is taking it a step further by adding a filter that processes page content, looking for <img> tags, and automatically inserts the appropriate srcset attribute.

There you have it. I welcome anyone who’s reading this to give the function a try in your WordPress site, and let me know how it goes!

The Something Manifesto, Part Two

Darts_in_a_dartboardThere have been plenty of manifestos over the years, perhaps the most famous being Marx’s The Communist Manifesto. The manifesto that has defined the first decade of the 21st century, or at least the decade’s online component, is without a doubt The Cluetrain Manifesto.

Defining Success

I have always harbored almost a knee-jerk disdain for Cluetrain, quite possibly just because I think its title is stupid. It doesn’t help that the first of its Lutheresque “95 theses” is:

Markets are conversations.

I don’t really believe this. Markets are places where people try to sell you stuff. Luring you into conversation is just a sales tactic. Everything that follows in Cluetrain is dependent upon this one central illusion: make the market look like it is two people engaging in a meaningful interaction, instead of simply exchanging money for goods and services. Even Homer Simpson’s inner voice knows the value of a $20 bill, and not since Ayn Rand has capitalism so effectively masqueraded as philosophy.

This doesn’t make the market evil, it just exaggerates the human value of the quest for profit. Which brings me back to the Jason Fried interview I linked to in part one. Fried says:

It really bothers me that the definition of success has changed from profits to followers, friends, and feed count. This crap doesn’t mean anything. Kids are coming out of school thinking, I want to start the next YouTube or Facebook. If a restaurant served more food than everybody else but lost money on every diner, would it be successful? No. But on the Internet, for some reason, if you have more users than everyone else, you’re successful. No, you’re not.

Fried is absolutely right about the dangers in the Internet era of equating popularity with success. But the original equation is no less dangerous. Does profit equal success? That depends. Is profit your goal?

Meeting your goals equals success.

The problem is that following this axiom requires that you have goals, and sadly that often seems too much to ask.

I think most people have an innate desire to matter. We want to feel like our lives are important, or at the very least, that they mean something. That’s been the essence of religion for thousands of years. Fame is an easy thing to latch onto in this regard: if everyone knows who I am, then I must be important. Eventually, though, this quest for fame is going to result in dissatisfaction, regardless of the outcome. Either you fail to become famous, languish in obscurity, and lament your lack of success, or you achieve the fame you seek, realize it’s a hollow victory, and continue to seek out one new fix after another. But they’re all the same, and you always come down.

The Freedom to Be Productive

Unwarranted hallowing of “The Market” aside, both Cluetrain and Jason Fried’s philosophy represent a prevailing attitude of this decade: that breaking down the old, rigid structures of the 20th century corporate world will produce happier, more productive employees/citizens/people. I agree. But there’s a major problem: it’s just really hard for a calcified corporate hierarchy to adapt to this kind of flexibility. Lots of companies have tried it, to be sure. I’ve been there. But the efforts are usually hampered by lack of enthusiasm and buy-in by the employees, lack of focus and direction by management, or sheer inertia.

At best small pockets — rogue departments — can collectively “break the rules” and implement a more flexible structure, but they’re destined to remain on the fringe. Or, a few of the principles will be implemented company-wide, but they’ll be so mutilated by that point that they result in absurdities like once-a-month “denim days” where employees have to pay (in the form of a charitable donation) for the “privilege” of dressing comfortably.

There’s another problem that doesn’t get stated explicitly in Inc.’s article on Jason Fried’s Facebook-like recitation of the daily minutiae of his life. He gets up before 7 AM. He does some work while he’s getting ready. He arrives at work (or works from home) around 10 AM, and stays until 6 PM. Then after his regimen of Fox TV, he may put in a few more hours of work at night. In other words, his job is his life. It’s integrated with other things, to be sure. He fits in plenty of non-work activities during the day. But work is always there. It’s no surprise that he’s single, no kids. There may not be a causal connection, and if there is, one can’t determine from the article in which direction it points. But the simple fact remains that a life this focused on work cannot simultaneously accommodate a relationship, much less kids.

This was the problem I had at my last job before I went freelance. In many ways, it was the ideal place for someone of my geeky persuasion to work. And I often lament that I am not a part of that world anymore. But the arrangement was unsustainable for me: developers pulling “all-nighters,” crashing on couches in the lobby, getting pizza delivered in at 10 PM, these are all standard practice. It’s a culture of work that expects a level of availability that someone who’s also responsible for two young children simply cannot afford to provide. But it’s an inherent element of the kind of “flexible” work environment these philosophies inspire.

And so it was that I set out on my own. The environment I’m attempting to create for myself is, in many ways, not unlike that which I left, or which I’ve been criticizing in the preceding paragraphs. The major difference is in the amount of time I am expected to devote to work (that is, billable hours) versus the other aspects of my life which, to many an employer’s chagrin, continue to exist. But this true freedom comes at a price: less billable hours means… less money. And not being on someone else’s payroll means I’m shouldering all of the risk of the operation. The business is mine to make into a success or to allow to become a failure. But at least it’s mine.

Call to action: Find ways to work that work for you.

To be continued…

The Something Manifesto, Part One

somethingI’ve been thinking a lot lately. Or, not so much thinking, but thinking it would be nice to have more time to think. Or more time to do anything. I want to be more productive, even if I’m not sure what I want to produce. I haven’t had time to figure that out yet.

I’ve noticed a convergence of ideas lately, both inside my own head and in the larger world, a world I increasingly interact with primarily via the Internet, despite the fact that I am fully capable of going outside and interacting with it directly. These ideas are mostly circling around a disturbing premise: the tools that are allowing us to share these ideas are consuming our ability to produce them in the first place.

I’ve become something of a Facebook and Twitter addict over the course of the past year. I need the constant affirmation they provide in the form of comments from acquaintances and strangers alike on the random scraps of brainstuff I frequently distribute via this medium. Comments tell me people know I exist. They make me feel important. Increasingly, they serve as a sterilized substitute for genuine human interaction.

But there may just be some hope yet: I’m seeing encouraging signs that I’m not alone in… uh… being alone. Joshua Wentz (of SIDEDOWN) laments the vacuous experience of Facebook. Jason Fried (of 37signals) tells Inc. how popularity on social networking sites does not equal success. Nick Kallen (of Twitter, no less!) discusses how our brains buckle under the sheer mass of information in the modern world.

And so, I present my manifesto. My statement of beliefs about… something. I’m just not sure what.

Family > Work > Social Networking

I need to prioritize. We all need to. What’s really the most important to us, or, more accurately, who is? Our interactions with the people who really mean something to us, who are a part of our daily existence, must come first. These people are our “family,” whether we’re related by blood or not, whether our relationships are legally recognized by the government or not.

Work is next. Work is what we do that matters to us. It’s not necessarily what we get paid to do — though if we’re lucky, we can sometimes make that happen. It’s what drives us and fulfills us.

Social networking? Well, now we begin to see its real place in the hierarchy of things. These tools can help us to reconnect with the people we care about but with whom we no longer share physical space. They can help us meet and develop meaningful relationships with people whose interests we share, but whose physical space we never have (and likely never will). But much of the time they simply provide needless distractions, inundating us with useless details about the lives of people who don’t really mean that much to us. Just because information exists, doesn’t mean it’s important.

Call to action: Delete your social networking bookmarks.

To be continued…

Election night liveblog HERE!

OK, I’m going to give this “liveblog” thing a shot. I’ll be posting timely updates here as I think of them, trapping every fleeting thought in amber and preserving it for subsequent humiliation. Don’t miss it! The page will automatically refresh every 5 minutes to annoy you keep you up-to-the-minute with the nonstop excitement that is bound to ensue.

11:37 PM ▸ They’re already talking automatic recount on the Senate race. Maybe it’s time for bed. For those of you who’ve hung in there with me, thanks for reading! Yes we can! And we did!

11:33 PM ▸ Al believes he’s going to win. I’m shocked. But no matter what happens, he says, “Know this: we have changed this country.”

11:30 PM ▸ Has Al Franken been drinking? I suppose that’s OK, we’re all celebrating our new president-elect. I met Al in person at the Minnesota State Fair — last year — and I promised him my vote. He got it. Let’s hope it counts.

11:25 PM ▸ What’s Coleman on about? Looks like he got a new haircut. Seems a bit premature for him to be up addressing his supporters though. Ugh. This Senate race is going to be long and painful.

11:16 PM ▸ Wow, a president who’s not just thinking of how much he can take from the next four years, but how much he — and we — can give to the world a century from now. Vision. We have it again.

11:09 PM ▸ “This victory alone is not the change we seek. It is only the chance to make that change.”

11:03 PM ▸ See, everyone? Obama = puppies! Yay!!!

11:01 PM ▸ I know whether you’ve won or lost plays a factor in this, but when McCain mentioned Obama, his supporters booed. When Obama mentioned McCain, his supporters cheered.

10:41 PM ▸ OK, I’m back, two Baileys-es later. Let’s see how the lesser races go. Come on, Al Franken!

9:40 PM ▸ Congratulations to Joe Biden… for winning re-election to his Senate seat. I’m going to put the computer away for a while and toast President Obama with a tasty beverage!

9:36 PM ▸ OK, we can stop talking about how a year ago everyone was thinking this would be a Clinton vs. Giuliani race. I do like how they’re tiptoeing around the obvious fact that Obama has California and the other West Coast states. None of what they are saying is even remotely relevant! It’s over!

9:19 PM ▸ Yes, folks, it’s over. The networks can’t “officially” call states where the polls are still open, but there’s no real doubt that Obama will carry California, Oregon, Washington and Hawaii. If he’s already got 207, plus California’s 55, that’ll put him at 262. (To say nothing of the other three states I just mentioned.) Eight more votes from any of the other states, which he’s certain to get, and it’s over.

9:16 PM ▸ Wow, John Murtha got re-elected despite his missteps in referring to his own constituents as racists and then, in his semi-apology, as rednecks.

9:04 PM ▸ Now Nate Silver joins me in calling it for Obama, as of 8:46 PM.

8:54 PM ▸ Taking a break now for the kids’ nighttime rituals, slightly abridged.

8:52 PM ▸ Tim Russert, we miss you and your whiteboard.

8:47 PM ▸ Hmmm… as this map is starting to fill in, it’s looking like a Civil War map. All of the northern states are blue; all of the southern states are red. Let’s see how Virginia and North Carolina go. It would certainly be symbolic if the old Confederate capital, at least, went for Obama.

8:33 PM ▸ Combining the call of Ohio with FiveThirtyEight.com‘s “safe” votes, we’re at 279. Folks, I think it’s over!

8:31 PM ▸ Virginia’s coming back in line… I’m giddy! 200-to-85 right now.

8:27 PM ▸ Obama wins Ohio! Big news!!! Jw can breathe a sigh of relief.

8:26 PM ▸ Now that Minnesota’s in for Obama, I’m waiting to hear about the Senate race and the 6th District House race. I also want to hear how the Minneapolis school board results turned out. If you want to homeschool, fine. But, if you ask me, a homeschooler simply doesn’t belong on the school board!

8:17 PM ▸ Ugh. The “I’m a PC” ads sucked bad enough before they were all shot on $20 Walmart webcams.

8:15 PMFiveThirtyEight.com is now saying Obama has 259 “safe” electoral votes. If they’re right, he only needs to snag 11 more out of the toss-up pool and it’s over.

8:14 PM ▸ I now have a mispronunciation that I hate more than “nucular.” It is not pronounced “pundint”!!!!

8:05 PM ▸ Grant Park, Chicago: They got their tickets “in” the Internet? Don’t you mean the “Inter-Tubes”?

8:04 PM ▸ I am now seeing the benefit of HD. There’s all kinds of extra data crammed into the sides of the screen. I guess we’ll be sticking with the broadcast networks now. (Too cheap for digital cable.)

8:03 PM ▸ Painting a map on the ice rink at Rockefeller Center. Sweet.

8:01 PM ▸ W00t! Obama wins Minnesota. Arizona TOO CLOSE TO CALL. Hmmm….

7:59 PM ▸ Flipped to KARE-11. Not that I really need to see these guys in High Definition. I thought the one dude was Newt Gingrich at first. *shudder*

7:55 PM ▸ MSNBC, you’re losing me. If I gave a crap what Tom Delay thinks, I’d watch Fox News.

7:53 PM ▸ Chatting with SLP over Facebook even though we’re sitting in the same room. This is ridiculous.

7:45 PM ▸ I wonder if the Republican Party is on track to be relegated to the margins the way the Democrats were in the ’50s, such as in 1952 and 1956 when (both times) Adlai Stevenson only won a small band of Deep South states against the Eisenhower juggernaut. I don’t think that transition is happening this year, but based on how things go over the next four years, the 2012 electoral map might look like a mirror image of the 1952 map.

7:38 PM ▸ I don’t think this is going to move as smoothly as I had initially hoped. Virginia was looking solid Obama over the last few days on FiveThirtyEight.com.

7:31 PM ▸ Virginia… ouch. Too close to call, but McCain is way ahead with roughly a third of the precincts reporting… THIS JUST IN — Elizabeth Dole lost her seat. That was a pretty nasty campaign.

7:27 PM ▸ OK, it’s on. We’re watching MSNBC. Ann Curry was just talking about white voters in North Carolina who said race was a factor. (I think it was North Carolina. Some southern state, at any rate.) Apparently 24% of white voters in that state said race was a factor, and among them 30% “still” (that’s a quote) voted for Obama. Isn’t it possible that race was a factor for some of them in a positive way? I’m white, and I think it’s about damn time we have a black president too!

7:25 PM ▸ Is it over? I just got home. I heard on NPR in the car that Obama took Pennsylvania. Big news. McCain has a steep climb to recover from this position.

5:23 PM ▸ This will probably be my only update-by-iPhone. The on-screen keyboard is just not designed for coding HTML. Anyway, I’m at the mall with the kids, having Chicken McNuggets shoved in my face. Not by choice. Oh well… the cashier at McDonalds gave me a free milk when she saw my Obama button. Let the redistribution begin!

2:27 PM ▸ OK, time to go think about something else for a while. I’ll be back when I just can’t stand it anymore.

1:56 PM ▸ Tick… tock… tick… tock…. Is it over yet?

11:54 AMMy Voting Story. Since I’m already starting to hear tales of woe from friends and acquaintances in other states, I felt like I should share my own story. Gloat, if you will. We decided to vote after the kids were off at school, so we ended up walking to our polling place (the Methodist church at the end of our block) around 9:15 AM. We talked to some neighbors along the way, who had already voted, and they mentioned that there had been a bit of a line earlier as people voted before work, but now things had tapered off.

We walked right in, no line, signed in, walked over to the ballot table, took our ballots to the little folding (and flimsy) voting carrels, marked ’em up, took them to the Tabulatron 2000™ (or whatever it’s called), fed them in, and that was it. Got our stickers and walked out. OK, the Tabulatron spit out my ballot at first so I had to give it a second try, but then it worked. I even distinctly heard the sound of the ballot dropping, intact, to the bottom of the big metal box inside, so I’m fairly sure it was not shredded.

Now, lest you get the impression that the electorate is staying home around here, that is not the case. The place was humming with people. It just happened that the capacity of the polling place was precisely matched to the number of people coming in to vote at that time. I could almost hear a Raymond Scott tune playing in the background.

Go Minneapolis!

11:39 AM ▸ Popcorn has been requested. Here you go…

11:23 AM ▸ He hasn’t even won yet and they’re already renaming buildings after him.

11:11 AM ▸ I managed to work for an hour. Now it’s time to get some lunch and think about the election some more. And post some asinine status updates on Facebook.

10:11 AM ▸ Currently on the U of M campus. Election buzz is tangible. Lots of Obama love. Also clean water amendment. Yay, sales tax! (I voted for that, too.)

9:25 AM ▸ The deed is done.

6:34 AM ▸ Let’s get things started by dropping in the MSNBC election dashboard. This will serve as the Al Michaels (or, if you’re old skool, Pat Summerall) to my John Madden.