How I adapted my blog to Google’s recipe search

Disclaimer: This is likely of interest primarily to other food bloggers.

Those who follow tech news may have heard of Google’s new recipe search, which was launched two weeks ago. Google has created a tab to search specifically for recipes, much like its searches for photos or news. The catch? In order to be included, your site has to meet certain coding standards.

This may or may not be good news for food bloggers. Most of us write in paragraph form — as opposed to, say, filling out a spreadsheet with quantities and ingredients — and don’t tag things such as ingredients, cooking time (do we even list that?) or rating (who among us lets people rate recipes?).

hRecipe is a microformat, which basically enables a machine to understand your site. While a human can easily tell if what you’ve written is a recipe and can spot the ingredient list, a computer won’t necessarily recognize either unless you tell it to do so, with specific tags — much like you tag text as bold or italic. Needless to say, it’s a lot of work to make our sites computer readable and thus eligible for the new search.

The merits for bloggers are discussed at Dianne Jacob’s site and on Food Blog Alliance. The advantage for users is that this search lets them look for recipes based on ingredients, prep time and calorie count. Google apparently informed major recipe sites about the change a year ago, which means they’ve had all that time to get ready. Currently, the only sites that show up in the search are the big recipe sites, plus a few large food blogs.

I like new technology, so I wasn’t adverse to trying to implement hRecipe on my own site. hRecipe-based searches may be increasingly used by other platforms and applications, not just Google. Plus — and I’m not gonna lie — I have a husband who is capable of doing the coding. What I was adverse to doing was updating and recoding every individual recipe. So I found some shortcuts that worked for the specific setup of my blog, and if you organize things like I do, they might work for you, too.

The bad news is that even if you do go through the trouble to implement hRecipe, Google rules that your pages pass its test and you then submit your site for inclusion, it may not be included. And if it is included, it may take months. That said, hopefully there will be advantages to making my (and your) site more computer-readable in any case.

Choosing a format

Google gives you several ways to make your site compliant with its recipe markup. One of them is hRecipe. In order to be a valid hRecipe, your recipe needs to include a title and at least one ingredient (meaning, they need to be marked). That’s it.

In order to create a preview, though, Google says it insists that you have at least two of the following tagged: prep time, cook time, total time, calories, rating, review count or image. Mind you, I’ve seen sites appear in the search that don’t seem to have all that information.

Applying hRecipe semi-automatically to old posts

It’s no big deal to implement minimum hRecipe markup on future recipes — the catch is applying it to your archive without excessive grunt work. That’s what these instructions address. Another advantage of automatically tagging recipes is it saves you work in the future — any post I write from now on will also have minimum hRecipe markup.

Our implementation of hRecipe relied on a few basic characteristics of my blog:

  • My blog runs on, and I can edit the theme
  • Not all my posts are recipes
  • I generally tag each post with a list of the main ingredients
  • Each recipe post has a custom field named “smallphoto” that I use to create thumbnails

The first item is important because this gave us the freedom to change the coding. The second is important because it meant I needed to tell the computer which posts were recipes and which weren’t — no use having a non-recipe post show up in the recipe search. The final two are important because they gave me a convenient way of isolating this data.

I decided to make my recipes meet the minimum needed for a preview by:

  • tagging recipe names
  • tagging ingredients by means of my tags
  • tagging photos by means of my thumbnail photos
  • tagging number of reviews based on my comment count Update: Thanks to some input from Elise of Simply Recipes, I’ve taken this out. Explanation follows.

IDENTIFYING POSTS AS RECIPES: First, I made a category for recipes. I called it “Recipe.” Then, I went through my list of posts, and using the “quick edit” option, tagged all relevant posts as recipes. This took an hour or two, but it was quicker than re-editing every recipe.

IDENTIFYING TAGS AS INGREDIENTS: Second, I labeled tags that were ingredients. My tags include any number of things — main ingredients, ethnicity, type of dish, etc. I went through my list of tags and added the description “ingredient” for anything that was an ingredient (if you hover over any given tag, it gives you the option of editing it). This also took an hour or two, but still, it was quicker than re-editing.

The other changes all involved coding — adding and changing things to index.php and functions.php. Both are files that are part of your theme, and they can be edited by clicking on Editor, which appears under Appearance. You need to be able to edit your files through your FTP interface should something go wrong — a mistake in code, which could be caused by a typo or if your blog theme isn’t structured like mine is, could take your entire blog offline, including WordPress’s admin page. In this case, the only way to fix it will be editing the file directly, through FTP. If you don’t understand what this means, don’t try this on your own.

CREATING NEW FUNCTIONS: First off, Eitan created the following four functions, which he inserted into my theme’s file functions.php:

// four functions to make site hrecipe compliant:
function hrecipe($value){
  if (in_category(291)) // make this the number of your recipe category
    echo $value.' ';

function the_hrecipe_tags( $before = null, $sep = ', ', $after = '' ){
        if ( null === $before )
                $before = __('Tags: ');

    $tags = get_the_tags();
    if (null != $tags && count($tags)>0){
        foreach ($tags as $tag){
                $tag_list[]= '<a class="tag '.$tag->description.'" rel="tag" href="'. get_tag_link($tag->term_id).'">'.$tag->name.'</a>';
                $tag_list[]= '<a class="tag" rel="tag" href="'. get_tag_link($tag->term_id).'">'.$tag->name.'</a>';
    if (isset($tag_list))
        echo $before . join($sep, $tag_list) . $after ;

function hrecipe_photo(){
  global $post;
  $smallphotourl = get_post_meta($post->ID, 'smallphoto', true);
  if ($smallphotourl <> ""){
    $smallphoto='<img src="'.$smallphotourl.'" alt="" style="display:none;" class="photo">';
    echo $smallphoto;
  echo '<span class="author" style="display:none;">Liz Steinberg</span>'; // change this to your name! 

// I've decided not to use this function for now, but here's the code anyway: 
function hrecipe_comments_popup_link() {
  $preString = '<span class="review hreview-aggregate"><!--span class="rating"><span class="average value-title" title=""></span></span--><span class="count">';
  $postString = '</span></span>';
  $zero = 'No Comments';
  $one = $preString . '1' . $postString . ' Comment';
  $more = $preString . '%' . $postString . ' Comments';
  $none = 'Comments Off';
  comments_popup_link($zero, $one, $more, '',$none);     

The first function tests whether a post is a recipe — namely, whether it is in category 291, which is my category for recipes. You can tell what number your recipe category is by going to the categories tab (under posts) and editing the category “Recipes.” In my case, it took me to the page — and that number, 291, is the category’s ID number.

The second function labels tags as ingredients if they have the description “ingredient.” Note that the word “ingredient” never appears in the function — basically, the function takes whatever is in the description field and uses it to mark the tag. It also makes all your other tags machine-readable — so things like “vegetarian” and “Israeli” also show up as descriptions, even if they won’t necessarily be used in Google’s search at the moment. Do not put any weird symbols, such as brackets, into the description field, because it could break your blog.

The third function inserts information that Google wants. It addresses specific issues with my blog — I have one isolated photo for every post, in a special custom field called “smallphoto,” but this smallphoto does not ever appear in posts. It makes the smallphoto — a thumbnail of my main photo — appear in the HTML, but as an invisible field (Yes, Google says not to tag invisible fields, but this passed their hRecipe markup test all the same). As a bonus, it also adds an invisible field with my name, so that I’m attributed as the author of the post. If you use this function, change the name to your own.

The fourth function takes the comment count and tags it as the number of reviews. Note that if your blog says something like “X pithy reflections” instead of “X comments,” you’ll need to change every reference to ‘Comments’ (in single tags).

Update: I chose not to use the comment function on advice from Elise of Simply Recipes, who actually spoke to the team at Google. They told her they do not want bloggers to mark comments as reviews, and apparently the one blog that appears in search results with comments marked as reviews was put there by Google as a test. Without this markup, my posts no longer contain enough data to produce a preview with Google’s testing tool. However, some of the sites that appear in Google’s recipe search also lack data for a full preview, yet the search shows the data they have anyway (photo, ingredients, etc.).

ADDING NEW FUNCTIONS TO YOUR ACTUAL CONTENT: Once we added these new functions, we incorporated them into index.php — the page that loads nearly every page on my blog, whether it’s my home page or individual posts.

Before the changes, the top half of my index.php page looked like this:

<?php get_header(); ?>	
	<div id="bloque">
		<div id="noticias">
		<?php if (have_posts()) : while (have_posts()) : the_post(); ?>
			<div class="entrada">
				<h2 id="post-<?php the_ID(); ?>"><a href="<?php the_permalink() ?>" rel="bookmark" title="Permanent Link to <?php the_title(); ?>"><?php the_title(); ?></a></h2>
				<small><?php the_time('F j, Y \a\t\ g:i a'); ?> | <?php the_tags(__('Tags: '), ', ', ' '); ?> | <?php comments_popup_link('No Comments', '1 Comment', '% Comments'); ?></small>
			<?php the_content("Continue reading ".the_title('', '', false)."...");  addThis();?>

Afterward, it looked like this:

<?php get_header(); ?>
	<div id="bloque">
		<div id="noticias">
		<?php if (have_posts()) : while (have_posts()) : the_post(); ?>
			<div class="<?php hrecipe('hrecipe'); ?>entrada">
				<h2 id="post-<?php the_ID(); ?>" <?php hrecipe('class="fn"'); ?>><a href="<?php the_permalink() ?>" rel="bookmark" title="Permanent Link to <?php the_title(); ?>"><?php the_title(); ?></a></h2>
<?php hrecipe_photo(); ?>
				<small><span class="published"><span class="value-title" title="<?php the_time('Y-m-d\TH:i:sP
'); ?>"> </span><?php the_time('F j, Y \a\t\ g:i a'); ?></span> | <?php the_hrecipe_tags(__('Tags: '), ', ', ' '); ?> | <?php hrecipe_comments_popup_link(); ?></small>  // I've since reverted to the old comments function 
			<?php the_content("Continue reading ".the_title('', '', false)."...");  addThis();?>

Note that the five things that changed are marked in red. Aside from implementing the four three functions we added to function.php, tags were added in order to make the date machine readable.

Here’s what the various functions do within my index.php page:

  • The function hrecipe checks whether the post is in the category “Recipe,” and if it is, it adds whatever you put between the parentheses into your code. In the first instance, it adds the style ‘hrecipe’ to the div that contains all the content in each post. In the second instance, it adds ‘class=”fn”‘ to my h2, the post name, thus identifying as the recipe’s name.
  • The function hrecipe_photo adds invisible data — a tagged photo and the author’s name. The invisible photo is just another version of the main photo that appears in every post, but I didn’t have an easy way to tag the photo that’s already there.
  • The new tags around WordPress’s function the_time makes the date machine-readable.
  • The function the_hrecipe_tags replaces the WordPress function the_tags, and it adds class=tag to all tags, and class=ingredient to tags that I marked as ingredients.
  • The function hrecipe_comments_popup_link had replaced WordPress’s function comments_popup_link, and it tagged the comment count as a review count. I’ve since taken it out.

TEST YOUR MARKUP: Once you think you’ve marked up your site, you can feed it into Google’s rich snippets test to see whether you meet the standards, and to see whether you have enough data for Google to agree to make a preview of your page to appear in searches.

Here’s what we got when we added the above code and tested a random page on my site:

Note that it created a preview, even though it doesn’t include a photo, and that it identified all the marked-up data — it found four ingredients, a publication date, a photo, a review count and lots of descriptive tags. There’s a warning, because Google wants a rating (between 1 and 5) to appear alongside the review count, and that’s not data I have.

In my latest post, I added some more data that Google wants — prep time. Now, when I tested that post, note that it used the image in the preview, apparently because it received more (unrelated) data.

Incorporating hRecipe into new posts

Compared to the above mess, adding hRecipe tags to new recipes as you go is relatively easy. You can copy some of the main tags off Google’s example. Click on the “microformats” link under the sample recipe.

There’s also a plugin for WordPress, hRecipe, that will give you a form and automatically mark up your text. I haven’t used it.

More info

Leave a Reply