Try Tuts+ Premium, Get Cash Back!
Integrating Google Rich Snippets Into a WordPress Theme

Integrating Google Rich Snippets Into a WordPress Theme

Tutorial Details
  • Program: WordPress
  • Version: 3.0+
  • Difficulty: Intermediate
  • Estimated Completion Time: 1.5 hour

We’re all familiar with the way Google presents search results – with a page title and a little snippet of text for each result. With Google Rich Snippets we can add useful information to the web search result snippet to make it stand out from other results and ultimately attract more visitors. While there are already plugins that provide this kind of functionality in WordPress, there are situations when relaying on a third party plugin is not advisable. In this tutorial, we are going to integrate the microdata format into WordPress theme markup to display a culinary recipe, and make it compatible with Google Rich Snippets’ requirements.


Introduction to Google Rich Snippets

Let’s take a look at an example of a rich snippet:

I’ve highlighted for you the snippets of additional information that Google “reads” from the page. As you can see, rich snippets add some really useful information to search engine results. In case of recipes that information includes a photo, recipe rating, calories and total time it takes to prepare the dish. All this additional information gives users much better sense of the content on the page, and makes it more likely that users will click on the link and visit your website.

The snippets for each content type look slightly different and provide information relevant to the specific content type.

How to Enable Rich Snippets?

The secret behind rich snippets is structured, semantic markup, that allows Google to understand the page’s content. So basically, all you have to do is properly markup your content to describe the particular type of information on your website. In this tutorial we will be focusing on a culinary recipe, but Google supports rich snippets for a number of other content types, namely:

  • Reviews
  • People
  • Products
  • Businesses and Organizations
  • Events
  • Music

For more information on rich snippets and content types, visit the Google Help Center.

When it comes to marking up your content, there are three markup formats to choose from:

  • microdata
  • microformats
  • RDFa

In this tutorial, we’ll be integrating microdata markup with schema.org properties, as recommended in Google rich snippets’ documentation. It’s worth noting, that the schema.org vocabulary is recognized not only by Google, but also by other major search providers – Yahoo! and Microsoft.

Visit Schema.org for more information and examples on how to implement it in your code.


Step 1 Creating Recipe Custom Post Type

Since we will be writing quite a lot of code, we’ll create a separate file called recipe-config.php, to hold all our snippets, and include it using the PHP function include. To do that, open the functions.php file in your current theme directory, and paste the following piece of code at the end:

include('recipe-config.php');

Now create a new file called recipe-config.php. All the code that follows should be added to that file.

Let’s start by creating a new Custom Post Type called Recipe.

add_action( 'init', 'register_my_culinary_recipe' );
  
function register_my_culinary_recipe() {
    $labels = array(
        'name'               => _x( 'Recipes', 'culinary_recipes' ),
        'singular_name'      => _x( 'Recipe', 'culinary_recipes' ),
        'add_new'            => _x( 'Add New', 'culinary_recipes' ),
        'add_new_item'       => _x( 'Add New Recipe', 'culinary_recipes' ),
        'edit_item'          => _x( 'Edit Recipe', 'culinary_recipes' ),
        'new_item'           => _x( 'New Recipe', 'culinary_recipes' ),
        'view_item'          => _x( 'View Recipe', 'culinary_recipes' ),
        'search_items'       => _x( 'Search Recipes', 'culinary_recipes' ),
        'not_found'          => _x( 'No Recipes found', 'culinary_recipes' ),
        'not_found_in_trash' => _x( 'No recipes found in Trash', 'culinary_recipes' ),
        'parent_item_colon'  => '',
        'menu_name'          => _x( 'Recipes', 'culinary_recipes' )
    );
	$args = array(
        'labels'              => $labels,
        'public'              => true,
        'publicly_queryable'  => true,
        'show_ui'             => true,
        'show_in_menu'        => true,
        'show_in_nav_menus'   => true,
        'exclude_from_search' => false,
        'hierarchical'        => false,
        'has_archive'         => true,
        'rewrite'             => array('slug' => 'recipe')
	);
	register_post_type( 'my_culinary_recipe', $args );  
}

Now if you go to the admin area, there should be a new option in the menu called “Recipes”. Don’t add any recipes just yet, because we need to add some custom meta boxes first.


Step 2 Adding Custom Meta Boxes

The Setup

Because we’ll need quite a few custom meta boxes of various types to store all the recipe specific data, I’m going to use the free Custom Meta Boxes and Fields for WordPress library to create them. Of course you could use any other script or create meta boxes from scratch, if you prefer.

Wptuts+ has a great tutorial on the topic of Reusable Custom Meta Boxes

First, we need to download the library from GitHub. As the author suggests, we will store all the script files in ‘lib/metabox‘ folder. So start with creating the ‘lib‘ folder in your theme or child theme, then add the ‘metabox‘ folder inside ‘lib‘. Unpack and upload all downloaded files to ‘/wp-content/themes/my-theme/lib/metabox‘.

Finally, we need to include the file init.php. Normally you’d include it in your functions.php file but we’ll do it in our recipe-config.php, since that’s where we store all the recipe specific functions.

function be_initialize_cmb_meta_boxes() {
    if ( !class_exists( 'cmb_Meta_Box' ) ) {
		require_once( 'lib/metabox/init.php' );
    }
}
add_action( 'init', 'be_initialize_cmb_meta_boxes', 9999 );

Once it’s done, we can start defining meta boxes.

Defining Meta Boxes

To qualify for Google Rich Snippets, we don’t need to provide all properties included in the specification, although each content type has a required minimum. In this tutorial, we are going to incorporate the following properties:

  • name
  • recipeCategory
  • image
  • description
  • ingredients
  • instructions
  • recipeYield
  • prepTime
  • cookTime
  • totalTime
  • datePublished
  • author

Note that we won’t have to create custom meta boxes for all the properties. For example, totalTime will be calculated based on prepTime and cookTime.

Let’s add some custom meta boxes, shall we?

$prefix = 'mcr_'; // Prefix for all fields

function mcr_create_metaboxes( $meta_boxes ) {
	global $prefix;
	$meta_boxes[] = array(
		'id'         => 'recipe-data',
		'title'      => 'Culinary Recipe',
		'pages'      => array('my_culinary_recipe'),
		'context'    => 'normal',
		'priority'   => 'high',
		'show_names' => true,
		'fields'     => array(
			//TITLE - TEXT
			array(
				'name' => __( 'Recipe Title', 'culinary_recipes' ),
				'id'   => $prefix . 'name',
				'type' => 'text',
			),
			//RECIPE TYPE - TEXT
			array(
				'name' => __( 'Recipe Type', 'culinary_recipes' ),
				'desc' => __( 'The type of dish: for example, appetizer, entree, dessert, etc.', 'culinary_recipes' ),
				'id'   => $prefix . 'type',
				'type' => 'text_medium',
			),
			// IMAGE UPLOAD
			array(
				'name'    => 'Recipe Image',
				'desc'    => 'Image of the dish being prepared.',
				'id'      => $prefix . 'image',
				'type'    => 'file',
				'save_id' => false, // save ID using true
				'allow'   => array('url', 'attachment') // limit to just attachments with array( 'attachment' )
			),
			//SUMMARY - TEXT
			array(
				'name' => __( 'Summary', 'culinary_recipes' ),
				'desc' => __( 'A short summary describing the dish.', 'culinary_recipes' ),
				'id'   => $prefix . 'summary',
				'type' => 'text',
			),
			//INGREDIENTS - TEXTAREA
			array(
				'name' => __( 'Ingredients', 'culinary_recipes' ),
				'desc' => __( 'Put each ingredient in seaprate line.', 'culinary_recipes' ),
				'id'   => $prefix . 'ingredients',
				'type' => 'textarea',
			),
			//DIRECTIONS - TEXTAREA
			array(
				'name' => __( 'Instructions', 'culinary_recipes' ),
				'desc' => __( 'Put each instruction in seaprate line.', 'culinary_recipes' ),
				'id'   => $prefix . 'instructions',
				'type' => 'textarea',
			),
			//YIELD - TEXT
			array(
				'name' => __( 'Yield', 'culinary_recipes' ),
				'desc' => __( 'Enter the number of servings or number of people served', 'culinary_recipes' ),
				'id'   => $prefix . 'yield',
				'type' => 'text_medium',
			),
			//PREP TIME - TITLE
			array(
				'name' => __( 'Prep time', 'culinary_recipes' ),
				'desc' => __( 'How long does it take to prep?', 'culinary_recipes' ),
				'type' => 'title',
				'id'   => $prefix . 'prep_title'
			),
			//PREP TIME HOURS - NUMBER
			array(
				'name' => __( 'Hours', 'culinary_recipes' ),
				'id'   => $prefix . 'prep_time_hours',
				'type' => 'number',
				'std'  => '0',
			),
			//PREP TIME MINUTES- NUMBER
			array(
				'name' => __( 'Minutes', 'culinary_recipes' ),
				'id'   => $prefix . 'prep_time_minutes',
				'type' => 'number',
				'std'  => '0',
			),
			//COOK TIME - TITLE
			array(
				'name' => __( 'Cooking time', 'culinary_recipes' ),
				'desc' => __( 'Total time of cooking, baking etc.', 'culinary_recipes' ),
				'type' => 'title',
				'id'   => $prefix . 'coking_title'
			),
			//COOKING TIME - TEXT
			array(
				'name' => __( 'Hours', 'culinary_recipes' ),
				'id'   => $prefix . 'cook_time_hours',
				'type' => 'number',
				'std'  => '0',
			),
			//COOKING TIME - TEXT
			array(
				'name' => __( 'Minutes', 'culinary_recipes' ),
				'id'   => $prefix . 'cook_time_minutes',
				'type' => 'number',
				'std'  => '0',
			)
		)
	);

	return $meta_boxes;
}

add_filter( 'cmb_meta_boxes' , 'mcr_create_metaboxes' );

With this piece of code we’ve created a meta box called “Culinary Recipe” that will show only on the Recipes post type edit screen.

The actual field definitions are stored as an array in the ‘fields‘ property. Let’s take a closer look:

array(
	'name' => __('Summary', 'culinary_recipes'),
	'desc' => __('A short summary describing the dish.', 'culinary_recipes'),
	'id' => $prefix .'summary',
	'type' => 'text',
),

Adding a new field is as easy as copying one of the array elements (shown above), and changing values for ‘name‘, ‘id‘, ‘desc‘ and ‘type‘. The Custom Metaboxes and Fields library offers a number of predefined field types, and a convenient method to define your own.

To facilitate separate input of hours and minutes for cook and prep time, I defined our own field type called ‘number‘. I utilized one of HTML5′s new input types – number, and created a simple validation function, casting integer type on the value supplied by the user.

add_action( 'cmb_render_number', 'rrh_cmb_render_number', 10, 2 );
function rrh_cmb_render_number( $field, $meta ) {
	echo '<input type="number" min="0" max="60" class="cmb_text_inline" name="', $field['id'], '" id="', $field['id'], '" value="', '' !== $meta ? $meta : $field['std'], '" />','<p class="cmb_metabox_description">', $field['desc'], '</p>';
}
add_filter( 'cmb_validate_number', 'rrh_cmb_validate_number' );

function rrh_cmb_validate_number( $new ) {
	return (int)$new;
}

Step 3 Displaying the Recipe

Now we are finally ready to write some markup. We could create a separate template file for our custom post type and place the markup directly in that template. Instead, we will be putting all the markup inside a function, and appending it to the post content with the_content() filter. This is important, because there are many plugins that add some kind of content, e.g. social media buttons, to the end of the post. This way we make sure, that all the plugin output is displayed below the recipe.

function mcr_display_recipe($content) {

	global $post;
	$recipe = '';

	if ( is_singular( 'my_culinary_recipe' ) ) {
		$recipe .= '<div class="recipe">';
			$recipe .= '<div itemscope itemtype="http://schema.org/Recipe" >';
				$recipe .= '<h2 itemprop="name">'. get_post_meta($post->ID,'mcr_name',true) .'</h2>';
				$recipe .= '<img class="alignright" itemprop="image" src="'. get_post_meta($post->ID,'mcr_image',true) .'" />';
				$recipe .= '<span class="mcr_meta"><b>Recipe type:</b> <time itemprop="recipeCategory">'. get_post_meta($post->ID,'mcr_type',true) .'</time></span>';
				$recipe .= '<span class="mcr_meta"><b>Yield:</b> <span itemprop="recipeYield">'. get_post_meta($post->ID,'mcr_yield',true) .'</span></span>';
				$recipe .= '<span class="mcr_meta"><b>Prep time:</b> <time content="'. mcr_time('prep','iso') .'" itemprop="prepTime">'. mcr_time('prep') .'</time></span>';
				$recipe .= '<span class="mcr_meta"><b>Cook time:</b> <time content="'. mcr_time('cook','iso') .'" itemprop="cookTime">'. mcr_time('cook') .'</time></span>';
				$recipe .= '<span class="mcr_meta"><b>Total time:</b> <time content="'. mcr_total_time('iso') .'" itemprop="totalTime">'. mcr_total_time() .'</time></span>';
				$recipe .= '</br>';
				$recipe .= '<hr />';
				$recipe .= '<span itemprop="description">'. get_post_meta($post->ID,'mcr_summary',true) .'</span><br />';
				$recipe .= '<h3>Ingredients:</h3> '. mcr_list_items('ingredients');
				$recipe .= '<h3>Directions:</h3> '. mcr_list_items('instructions');
				$recipe .= '<span class="mcr_meta">Published on <time itemprop="datePublished" content="'. get_the_date('Y-m-d') .'">'. get_the_date('F j, Y') .'</time></span>';
				$recipe .= '<span class="mcr_meta">by <span itemprop="author">'. get_the_author() .'</span></span>';
			$recipe .= '</div>';
		$recipe .= '</div>';
	}

	return $content . $recipe;
}
add_filter('the_content', 'mcr_display_recipe', 1);

Let’s get over the code. First, we pull the global $post object, which gives us access to various useful information about the post being displayed.

Then we use the conditional tag is_singular() to check if a single post of the type ‘my_culinary_recipe‘ is currently being displayed. This is because we didn’t create a separate template for our custom post type and thus WordPress is using the more general single.php template (or index.php if there’s no single.php) to display the recipe. Using the if statement we make sure that recipe markup won’t be displayed on regular posts.

Finally, we retrieve the recipe data using the get_post_meta() function, and place it inside the markup structured according to the microdata format.

Helper Functions

You might notice that I used some additional functions – mcr_time(), mcr__total_time() and mcr_list_items() to retrieve and prepare the data for display. Let’s take a look!

Time related properties (prepTime, cookTime and totalTime) expect values in ISO 8601 duration format. To account for that, both of our time related functions will take a format as a parameter, and prepare output accordingly.

function mcr_time($type = 'prep', $format = null) {

	global $post;

	$hours = get_post_meta($post->ID,'mcr_'.$type.'_time_hours',true);
	$minutes = get_post_meta($post->ID,'mcr_'.$type.'_time_minutes',true);
	$time = '';
	if ($format == 'iso') {
		if ($hours > 0) {
			$time = 'PT'.$hours.'H';
			if($minutes > 0) {
				$time .= $minutes.'M';
			}
		}
		else {
			$time = 'PT'.$minutes.'M';
		}
	}
	else {
		if ($hours > 0) {
			if ($hours == 1) {
				$time = $hours.' hour ';
			}
			else {
				$time = $hours.' hrs ';
			}
			if ($minutes > 0) {
				$time .= $minutes.' mins';
			}
		}
		else {
			$time = $minutes.' mins';
		}
	}
	return $time;
}

The mcr_time() function prepares output for cook and prep times, it accepts two parameters:

  • $type (required) is the type of time we want to display. Accepts two values – ‘prep(default) or ‘cook
  • $format (optional) – indicates that output should be formatted according to ISO 8601 duration format. Accepts only one value – ‘iso‘.
function mcr_total_time($format = null) {

	global $post;
	$prep_hours = get_post_meta($post->ID,'mcr_prep_time_hours',true);
	$prep_minutes = get_post_meta($post->ID,'mcr_prep_time_minutes',true);
	$cook_hours = get_post_meta($post->ID,'mcr_cook_time_hours',true);
	$cook_minutes = get_post_meta($post->ID,'mcr_cook_time_minutes',true);
	$total_minutes = ($prep_hours + $cook_hours)*60 + $prep_minutes + $cook_minutes;
	$hours = 0;
	$minutes = 0;

	if ($total_minutes >= 60) {
		$hours = floor($total_minutes / 60);
		$minutes = $total_minutes - ($hours * 60);
	}
	else {
		$minutes = $total_minutes;
	}
	$total_time = '';
	if ($format == 'iso') {
		if ($hours > 0 ) {
			$total_time = 'PT'.$hours.'H';
			if ($minutes > 0) {
				$total_time .= $minutes.'M';
			}
		}
		else {
			$total_time = 'PT'.$minutes.'M';
		}
	}
	else {
		if ($hours > 0 ) {
			if ($hours == 1) {
				$total_time = $hours.' hour ';
			}
			else {
				$total_time = $hours.' hrs ';
			}
			if ($minutes > 0) {
				$total_time .= $minutes.' mins';
			}
		}
		else {
			$total_time = $minutes.' mins';
		}
	}
	return $total_time;
}

The mcr_total_time() function calculates and prepares output for recipe total time. Accepts only one parameter – $format, analogous to the $format parameter in the mcr_time() function.

The last helper function displays lists of items – ingredients or instructions, according to the $type parameter.

function mcr_list_items($type = 'ingredients') {

	global $post;

	if (get_post_meta($post->ID, 'mcr_'. $type, true)) {
		$get_items = get_post_meta($post->ID, 'mcr_'. $type, true);
		$items = explode("\r", $get_items);
		$list = '';
	}
	else {
		return;
	}
	if ($type=='ingredients') {
		$list .= '<ul>';
		foreach ($items as $item) {
			$list .= '<li><span itemprop="ingredients">' . trim($item) . '</span></li>';
		}
		$list .= '</ul>';
	}
	elseif ($type=='instructions') {
		$list .= '<ol itemprop="recipeInstructions">';
		foreach ($items as $item) {
			$list .= '<li>' . trim($item) . '</li>';
		}
		$list .= '</ol>';
	}
	else {
		$list .= 'Invalid list type.';
	}
	return $list;
}

Now it’s time to add some content. Navigate to the Recipes section in the administration area, and add a recipe. The output might need some styling, but if you view the post, you should see the recipe below regular content.

That’s it! The only thing left, is to check if our markup is correct with the rich snippet testing tool from Google.

This is the rich snippet preview generated from our HTML markup:

You can test your markup by supplying either a URL or a code snippet to the testing tool.

Once you’ve added rich snippets markup, wait for the Google crawler to discover it. When Google notices the new markup, it should start displaying rich snippets for your website in search results. You can also submit a request form, to tell Google about rich snippets on your website, but you should give it some time first.


Conclusion

In this tutorial I showed you how to integrate a microdata format with a schema.org vocabulary to display culinary recipes. This example should serve you as a blueprint that you can use to enable rich snippets for other content types. Have you used Google Rich Snippets for anything in your projects? Let us know in the comments below.

Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • Pingback: Integrating Google Rich Snippets Into a WordPress Theme | Qtiva

  • http://www.foralien.com Anna

    Thank you for the idea! I actually never thought of implementing such a thing. Now it seems as great advantage in proper place.

  • Artur Bodera

    Thanks! That’s what I needed… there are several tutorials on this, but none comes close to this one. I finally got google to display mi snippets!

  • Web Dev

    Hi Alexander, Welcome to WP Tuts.

    This is awesome … really awesome … Its going to increase the click through rate for sure.

    I was looking for this tutorial around the web for some time now. Bookmarked your website too. I hope to see more of you in this site in the future.

    • http://webtuts.pl Aleksandra Laczek
      Author

      Actually, it’s Alexandra :) and I’m glad you find this tutorial useful.

  • http://www.antsmagazine.com Nahid

    Wow, Brilliant tutorial this is something that I was looking for from a while.

  • http://www.customicondesign.com/ Custom Icon Design

    High quality tutorial, from this tutorial we can learn custom post type and meta box. and how to display it. good job.

  • http://cloudofthemes.com Connor Crosby

    Wow, I love the level of detail in this tutorial. I hadn’t thought of adding these types of snippets before. Definitely considering now. Thanks :)

  • http://www.sanjaykhemlani.com/ sanjay

    Great timing! I am creating a restaurant website that offers free recipes, and this is just what I need, thank a lot for this :)

  • http://cyniccity.wordpress.com/ Me

    Brilliant — i have just started playing with wp thanx

  • http://www.linetoweb.com Raj Mehta

    Nice tutorial

    • puutarha

      I am whit you – very very nice job gys! Puutarha

  • http://john-mulligan.com John

    This is really deep. I got rich snippets to work with having my google+ profile image as the author of posts through the directions they provide, but hadno idea you could do all of this and get your content to be featured also!

  • Pingback: WordPress rolls out new widgets for bloggers | Open Knowledge

  • http://paulpela.com Paweł Pela

    This is awesome and right in time! I wanted to get into RDF and this is a great starting point to get going! Thanks!

  • martin

    ok, total noob here…

    can somebody show me an example on how to call the data from the metaboxes onto a page?

    say, for the recipe title, is it something like this:

    ID,’mcr_name’); ?>

    thanks!

    • martin

      i have to never work while blood sugar is low… a late lunch took care of things. i answered my own question:

      <?php if(get_post_meta($post->ID, ‘mcr_name’, true)) {echo get_post_meta($post->ID, ‘mcr_name’, true);}?>

  • martin

    last try, i promise:

    <?php get_post_meta($post->ID,’mcr_name’); ?>

  • http://wpninja.pl Szymon

    Great article Aleksandra. Keep it up!

  • Pingback: NET+ Best of Tuts+ in July 2012 via buypappa.com | Buypappa blog

  • http://wordpressguru.com.au Wordpress Dev

    I once implemented these feature on one of my website.

    Amazing thing is it stands out on the search results, gives your site credibility and increases the click through rate.

    Its better to use it on Post to rather than custom post, good for SEO perspective if possible. But this tutorial is well written and informative.

    • http://freshingly.com Ros Freshingly

      Hi WordPress Dev,
      I also think that it is more great to use regular posts for this. Since we are not using custom post type all the time. Is there any tutorial you can refer to implement this to regular posts? that will be very nice.
      Really need your help for this :)

      • http://webtuts.pl Aleksandra Laczek
        Author

        It’s fairly easy to do that following this tutorial. You just skip step 1 (Creating custom post type), and in steps 2 and 3 replace ‘my_culinary_recipe’ with ‘post’.

        Hope that helps!

  • Pingback: Best of Tuts+ in July 2012 | DigitalMofo

  • Pingback: VEC+ Best of Tuts+ in July 2012 via buypappa.com | Buypappa blog

  • Pingback: Best of Tuts+ in July 2012 | Shadowtek Hosting and Design Solutions

  • Pingback: PSD+ Best of Tuts+ in July 2012 via buypappa.com | Buypappa blog

  • Pingback: Best of Tuts+ in July 2012 | SearchPsd Blog

  • Pingback: Best of Tuts+ in July 2012 | Clixto7

  • http://www.designforce.us Hafeez Ansari

    Its really nice tutorial regarding rich snippets. This is exactly what I was searching for many hours. Thank you for sharing. :)

  • Pingback: Today's Links - Graphic Design Norwich and other oddities!

  • http://www.hostyasui.com govinda

    Yep, its really cool tutorial on rich snippets+ custom post types too :) I really liked it .

  • http://www.benhgout.com Gout Solution

    Can you explaint for me step 3 I can’t do

  • http://burano-condo.com Larissa

    Thanks Aleksandra for the detailed tutorial.
    I have been using wordpress because it is easy for someone like me who isn’t an expert at coding to be able still to create great websites. Adding such snippets is quite involved and requires a lot of code as you demonstrated. Do you know if there is a widget on wordpress that would be able to do that automatically by just having to type in the schema.org category ?

  • Pingback: WordPress: Rich snippets for wordpress? - Quora

  • http://webapprater.com Mike

    Hi, I have a review blog. But i use the standard blog post (not custom one) and use GTStar rating plugin for star rating ? How can i make the rich snippet ? Any reference please

  • http://sunrise-bg.com Dimitar

    Very useful guide, but what if you update your theme, or some kind of child theme will do the job well (i’m not very familliar with child themes as i recently try to use them)

  • http://www.artigatimit.com Nerti

    Hello!

    Nice article!

    What about adding ingredients on the actual post format?

    Thanks!

  • http://www.whatsthebigidea.com David Radovanovic

    If only I read this back in July, this was a perfect solution to a chefs website insead of the plugin route. Could the function be rewritten for other important meta like Author and Publisher?

  • Knikky224

    How did you get the rating show in google?

  • Helena

    Hi
    This would be fantastic! And it seems to work for others but not for me boho: (

    I have a child theme of Twenty eleven with just a stylesheet and a function file. I do not know if I’m stupid but shouldn’t the recipes be included with all the other posts on the index page. Or do I need a special function call on a new template of the index. I have added a recipe and published it. But as it is now, it appears not at all. Neither the index or on a single page.

    I downloaded your source files after my not seemed to work. You had missed a bit in the beginning, which I changed. Everything comes up in admin. I get no error messages.

    Please help me. Thanks so much in advance Helena
    (sorry for my bad English is not my first language)

  • Richard Wright

    I tried this and wrote a post.

    But at the end I tried to view and it said “Apologies, but the page you requested could not be found”.

    The post shows up when I do a search, but there is nothing there when I click on it.

    _x( ‘Recipes’, ‘culinary_recipes’ ),
    ‘singular_name’ => _x( ‘Recipe’, ‘culinary_recipes’ ),
    ‘add_new’ => _x( ‘Add New’, ‘culinary_recipes’ ),
    ‘add_new_item’ => _x( ‘Add New Recipe’, ‘culinary_recipes’ ),
    ‘edit_item’ => _x( ‘Edit Recipe’, ‘culinary_recipes’ ),
    ‘new_item’ => _x( ‘New Recipe’, ‘culinary_recipes’ ),
    ‘view_item’ => _x( ‘View Recipe’, ‘culinary_recipes’ ),
    ‘search_items’ => _x( ‘Search Recipes’, ‘culinary_recipes’ ),
    ‘not_found’ => _x( ‘No Recipes found’, ‘culinary_recipes’ ),
    ‘not_found_in_trash’ => _x( ‘No recipes found in Trash’, ‘culinary_recipes’ ),
    ‘parent_item_colon’ => ”,
    ‘menu_name’ => _x( ‘Recipes’, ‘culinary_recipes’ )
    );
    $args = array(
    ‘labels’ => $labels,
    ‘public’ => true,
    ‘publicly_queryable’ => true,
    ‘show_ui’ => true,
    ‘show_in_menu’ => true,
    ‘show_in_nav_menus’ => true,
    ‘exclude_from_search’ => false,
    ‘hierarchical’ => false,
    ‘has_archive’ => true,
    ‘rewrite’ => array(‘slug’ => ‘recipe’)
    );
    register_post_type( ‘my_culinary_recipe’, $args );
    }
    function be_initialize_cmb_meta_boxes() {
    if ( !class_exists( ‘cmb_Meta_Box’ ) ) {
    require_once( ‘lib/metabox/init.php’ );
    }
    }
    add_action( ‘init’, ‘be_initialize_cmb_meta_boxes’, 9999 );
    $prefix = ‘mcr_’; // Prefix for all fields
    function mcr_create_metaboxes( $meta_boxes ) {
    global $prefix;
    $meta_boxes[] = array(
    ‘id’ => ‘recipe-data’,
    ‘title’ => ‘Culinary Recipe’,
    ‘pages’ => array(‘my_culinary_recipe’),
    ‘context’ => ‘normal’,
    ‘priority’ => ‘high’,
    ‘show_names’ => true,
    ‘fields’ => array(
    //TITLE – TEXT
    array(
    ‘name’ => __( ‘Recipe Title’, ‘culinary_recipes’ ),
    ‘id’ => $prefix . ‘name’,
    ‘type’ => ‘text’,
    ),
    //RECIPE TYPE – TEXT
    array(
    ‘name’ => __( ‘Recipe Type’, ‘culinary_recipes’ ),
    ‘desc’ => __( ‘The type of dish: for example, appetizer, entree, dessert, etc.’, ‘culinary_recipes’ ),
    ‘id’ => $prefix . ‘type’,
    ‘type’ => ‘text_medium’,
    ),
    // IMAGE UPLOAD
    array(
    ‘name’ => ‘Recipe Image’,
    ‘desc’ => ‘Image of the dish being prepared.’,
    ‘id’ => $prefix . ‘image’,
    ‘type’ => ‘file’,
    ‘save_id’ => false, // save ID using true
    ‘allow’ => array(‘url’, ‘attachment’) // limit to just attachments with array( ‘attachment’ )
    ),
    //SUMMARY – TEXT
    array(
    ‘name’ => __( ‘Summary’, ‘culinary_recipes’ ),
    ‘desc’ => __( ‘A short summary describing the dish.’, ‘culinary_recipes’ ),
    ‘id’ => $prefix . ‘summary’,
    ‘type’ => ‘text’,
    ),
    //INGREDIENTS – TEXTAREA
    array(
    ‘name’ => __( ‘Ingredients’, ‘culinary_recipes’ ),
    ‘desc’ => __( ‘Put each ingredient in seaprate line.’, ‘culinary_recipes’ ),
    ‘id’ => $prefix . ‘ingredients’,
    ‘type’ => ‘textarea’,
    ),
    //DIRECTIONS – TEXTAREA
    array(
    ‘name’ => __( ‘Instructions’, ‘culinary_recipes’ ),
    ‘desc’ => __( ‘Put each instruction in seaprate line.’, ‘culinary_recipes’ ),
    ‘id’ => $prefix . ‘instructions’,
    ‘type’ => ‘textarea’,
    ),
    //YIELD – TEXT
    array(
    ‘name’ => __( ‘Yield’, ‘culinary_recipes’ ),
    ‘desc’ => __( ‘Enter the number of servings or number of people served’, ‘culinary_recipes’ ),
    ‘id’ => $prefix . ‘yield’,
    ‘type’ => ‘text_medium’,
    ),
    //PREP TIME – TITLE
    array(
    ‘name’ => __( ‘Prep time’, ‘culinary_recipes’ ),
    ‘desc’ => __( ‘How long does it take to prep?’, ‘culinary_recipes’ ),
    ‘type’ => ‘title’,
    ‘id’ => $prefix . ‘prep_title’
    ),
    //PREP TIME HOURS – NUMBER
    array(
    ‘name’ => __( ‘Hours’, ‘culinary_recipes’ ),
    ‘id’ => $prefix . ‘prep_time_hours’,
    ‘type’ => ‘number’,
    ‘std’ => ’0′,
    ),
    //PREP TIME MINUTES- NUMBER
    array(
    ‘name’ => __( ‘Minutes’, ‘culinary_recipes’ ),
    ‘id’ => $prefix . ‘prep_time_minutes’,
    ‘type’ => ‘number’,
    ‘std’ => ’0′,
    ),
    //COOK TIME – TITLE
    array(
    ‘name’ => __( ‘Cooking time’, ‘culinary_recipes’ ),
    ‘desc’ => __( ‘Total time of cooking, baking etc.’, ‘culinary_recipes’ ),
    ‘type’ => ‘title’,
    ‘id’ => $prefix . ‘coking_title’
    ),
    //COOKING TIME – TEXT
    array(
    ‘name’ => __( ‘Hours’, ‘culinary_recipes’ ),
    ‘id’ => $prefix . ‘cook_time_hours’,
    ‘type’ => ‘number’,
    ‘std’ => ’0′,
    ),
    //COOKING TIME – TEXT
    array(
    ‘name’ => __( ‘Minutes’, ‘culinary_recipes’ ),
    ‘id’ => $prefix . ‘cook_time_minutes’,
    ‘type’ => ‘number’,
    ‘std’ => ’0′,
    )
    )
    );
    return $meta_boxes;
    }
    add_filter( ‘cmb_meta_boxes’ , ‘mcr_create_metaboxes’ );
    function mcr_display_recipe($content) {
    global $post;
    $recipe = ”;
    if ( is_singular( ‘my_culinary_recipe’ ) ) {
    $recipe .= ”;
    $recipe .= ”;
    $recipe .= ”. get_post_meta($post->ID,’mcr_name’,true) .”;
    $recipe .= ‘ID,’mcr_image’,true) .’” />’;
    $recipe .= ‘Recipe type: ‘. get_post_meta($post->ID,’mcr_type’,true) .”;
    $recipe .= ‘Yield: ‘. get_post_meta($post->ID,’mcr_yield’,true) .”;
    $recipe .= ‘Prep time: ‘. mcr_time(‘prep’) .”;
    $recipe .= ‘Cook time: ‘. mcr_time(‘cook’) .”;
    $recipe .= ‘Total time: ‘. mcr_total_time() .”;
    $recipe .= ”;
    $recipe .= ”;
    $recipe .= ”. get_post_meta($post->ID,’mcr_summary’,true) .”;
    $recipe .= ‘Ingredients: ‘. mcr_list_items(‘ingredients’);
    $recipe .= ‘Directions: ‘. mcr_list_items(‘instructions’);
    $recipe .= ‘Published on ‘. get_the_date(‘F j, Y’) .”;
    $recipe .= ‘by ‘. get_the_author() .”;
    $recipe .= ”;
    $recipe .= ”;
    }
    return $content . $recipe;
    }
    add_filter(‘the_content’, ‘mcr_display_recipe’, 1);
    ?>

    • valentina martino

      set to default permealink, the set them again to personalized

  • CouponEasy

    I’ve been searching for this solution for my coupons site. Now I can easily integrate Google rich snippets on my WordPress site. Thank you so much for the solution this informative article.

  • http://www.michielvandijk.nl MVD

    Hi, Thanks for this great tutorial, Verry helpfull indeed!
    However my experience is that neither googles structured data testing tool nor google search results shows the image you put in the content as shown above. The only way you’ll get a profilepicture in your search result is to link your google profile which I find NOT verry pretty cause it’ll show your circles from google and the lot as well.

    If you have any fix for this please let me know

  • tom connell

    looks ideal for my needs – bit beyond me though – I am after the same thing but for music files – can anyone do this for me? please send estimate to remixdj01@gmail.com

    CHEERS

    • tom connell

      in fact – I need a quote for this for both music recordings and playlists rich snippets

  • Pingback: TOP 5 USEFUL WORDPRESS TUTORIALS | Free WordPress Themes and Plugins

  • http://twitter.com/KeyDatabase KeyDatabase

    Thanks you to suggest us a better way of implementing rich spinets in Google search…

  • http://twitter.com/lemonthirst lemonthirst

    Thank you! Very good post, if i am going to start my cooking blog. Any tuts on how to integrate the meta part into a page/post template? Running in circles around here

  • Victor

    I have a question?

    this trick does work with every theme?

    or is there a theme perfect for this?

  • B. Chamberlain

    I was very happy to come across this tutorial in a Google search; it has made me want to learn PHP more than ever. I wonder if anybody has source code for other types of content? I am particularly interested in musical recordings and playlists.

  • Zaiyan Khan

    Any tutorial to add music rich snippet please.