Give 1-on-1 coaching with a French chef  Cooking, culinary career or restaurant. E-gift card, from $150. Give an e-gift card
Skip to content

Bouquet Garni: Classic French Herb Bundle for Stocks & Sauces

Prep5 min
Total5 min
Yield1 Bouquet Garni
LevelBeginner
 
 
About This Recipe

Learn how to make a bouquet garni, the classic French bundle of parsley stems, thyme and bay leaf used to flavour stocks, soups, sauces and braises. Includes tying and removal tips.

Scale This Recipe

Servings

Ingredients

Units
  • 5 sprigs Parsley,
  • 3 sprigs Fresh thyme
  • 10 whole Black
  • 1 large Bay leaf
  • 1 small — green part only

Instructions

  1. 1

    Place the bay leaf, thyme, parsley, and celery on one piece of green leek. Cover with the remaining piece of green leek. Tie securely with fine string, leaving a length of string attached so that the can be easily retrieved.

Take It Further

Master the techniques behind this dish

This recipe is one of 320 in the OCS library — structured into 38 courses through the OCRS™ learning system. Pick a course and learn the technique behind it.

Tools Used in This Recipe

KitchenAid
Immersion Blender
Victorinox
8" Chef's Knife
All-Clad
Heavy-Bottom Stock Pot
Chef's Notes

Taste as you build this dish and adjust the seasoning at each stage — that habit alone will improve almost anything you cook. You'll find techniques like this one across our full course library.

If you'd ever like hands-on guidance for your own kitchen or restaurant, I also offer 1-on-1 coaching through OCS, or you can reach me directly for consulting at 911ChefEric.com.

— Chef Eric

Ready to cook like a professional?

38 structured courses. 320 recipes. OCRS™ learning paths. Certificates. Coaching.

Keep learning

Learn the technique behind the recipe.

Recipes come out right when you understand the method. Chef Eric’s courses teach the foundations step by step — knife skills, stocks, soups and classic French technique — with video lessons and short quizzes. Not sure where to start? OCRS™ will build your roadmap in five questions.

Scroll to Top
$ingredients_raw = get_post_meta( $post_id, '_recipe_ingredients', true ); $instructions_raw = get_post_meta( $post_id, '_recipe_instructions', true ); if ( ! function_exists( 'ocs_recipe_json_decode' ) ) { /** Decode recipe JSON; if unescaped quotes broke it, rebuild the rows field by field. */ function ocs_recipe_json_decode( $raw, $fields ) { $d = json_decode( $raw, true ); if ( is_array( $d ) ) { return $d; } $rows = array(); $pat = '/\{' . implode( ',', array_map( function ( $f ) { return '"' . $f . '":(?:"([\s\S]*?)"|(\d+))'; }, $fields ) ) . '\}(?=,\{|\]\s*$)/'; if ( preg_match_all( $pat, (string) $raw, $m, PREG_SET_ORDER ) ) { foreach ( $m as $row ) { $r = array(); foreach ( $fields as $i => $f ) { $v = isset( $row[ 2 * $i + 1 ] ) && '' !== $row[ 2 * $i + 1 ] ? $row[ 2 * $i + 1 ] : ( $row[ 2 * $i + 2 ] ?? '' ); $r[ $f ] = str_replace( '\\"', '"', $v ); } $rows[] = $r; } } return $rows; } } $ingredients = $ingredients_raw ? ocs_recipe_json_decode( $ingredients_raw, array( 'group', 'amount', 'unit', 'name', 'notes' ) ) : []; $instructions = $instructions_raw ? ocs_recipe_json_decode( $instructions_raw, array( 'step', 'group', 'text' ) ) : []; $cuisines = get_the_terms( $post_id, 'recipe_cuisine' ); $techniques_tax = get_the_terms( $post_id, 'recipe_technique' ); $difficulty_tax = get_the_terms( $post_id, 'recipe_difficulty' ); $meal_type_tax = get_the_terms( $post_id, 'recipe_meal_type' ); function ocs_format_time( $minutes ) { if ( ! $minutes || $minutes == 0 ) return null; $minutes = intval( $minutes ); if ( $minutes < 60 ) return $minutes . ' min'; $h = floor( $minutes / 60 ); $m = $minutes % 60; return $m > 0 ? $h . 'h ' . $m . 'min' : $h . 'h'; } // Bug 2/3 fix: strip raw HTML tags and corrupted rich-editor fragment data // that sometimes leaked into the original WPRM notes field on import. function ocs_clean_chefs_note( $text ) { if ( empty( $text ) ) return ''; // Strip Slate.js / rich-editor clipboard fragment junk (long base64-like blobs) $text = preg_replace( '/data-slate-fragment="[^"]*"/i', '', $text ); $text = preg_replace( '/]*>/i', '', $text ); $text = str_replace( '', '', $text ); // Strip any remaining tags except basic formatting, keep only readable text + links $text = wp_strip_all_tags( $text ); $text = trim( $text ); return $text; } $prep_display = ocs_format_time( $prep_time ); $cook_display = ocs_format_time( $cook_time ); $total_display = ocs_format_time( $total_time ); $cuisine_name = ( $cuisines && ! is_wp_error( $cuisines ) ) ? implode( ', ', wp_list_pluck( $cuisines, 'name' ) ) : ''; $difficulty_name = ( $difficulty_tax && ! is_wp_error( $difficulty_tax ) ) ? $difficulty_tax[0]->name : ''; $meal_type_name = ( $meal_type_tax && ! is_wp_error( $meal_type_tax ) ) ? $meal_type_tax[0]->name : ''; // ─── CONFIRMED COURSE LIST (real names only — no invented courses) ──── // URL pattern verified live: /product/{slug}-online-course/ $confirmed_courses = [ 'Food Safety Course 101', 'Food Handler Certificate', 'Kitchen Equipment Basics', 'Knife Skills & Basic Cuts', 'Knife Skills & Vegetable Cuts', 'Professional Vegetable Cuts', 'Stock Making 101', 'Stock Making Fundamentals', 'White Stocks Making', 'Brown Stocks Making', 'Vegetable Stocks Making', 'Soups Making 101', 'Seafood Soups Mastery', 'Clear Soups Mastery', "Cold & World's Soups", "Hors d'Oeuvres Mastery", 'Restaurant Mindset and Strategy', 'Business Planning for Restaurants', ]; function ocs_course_url( $course_name ) { // Verified live course URLs — pulled directly from /all-courses/ on // 2026-07-01. Do not regenerate slugs automatically; several course // names don't follow a predictable pattern (word order, added/omitted // words), so every entry here is a real, confirmed URL. $course_urls = [ 'Food Safety Course 101' => '/product/food-safety-course-101/', 'Food Handler Certificate' => '/product/courses-food-handler-certificate-online/', 'Kitchen Equipment Basics' => '/product/kitchen-equipment-fundamentals-online-course/', 'Knife Skills & Basic Cuts' => '/product/knife-safety-techniques-online-course/', 'Knife Skills & Vegetable Cuts' => '/product/knife-skills-vegetable-cuts-online-course/', 'Professional Vegetable Cuts' => '/product/vegetable-cuts-online-course/', 'Stock Making 101' => '/product/stock-making-101-online-course/', 'Stock Making Fundamentals' => '/product/stock-making-fundamentals-online-course/', 'White Stocks Making' => '/product/white-stocks-making-online-course/', 'Brown Stocks Making' => '/product/brown-stocks-making-online-course/', 'Vegetable Stocks Making' => '/product/vegetable-stocks-making-online-course/', 'Soups Making 101' => '/product/soups-making-101-online-course/', 'Seafood Soups Mastery' => '/product/seafood-soups-mastery-online-course/', 'Clear Soups Mastery' => '/product/clear-soups-mastery-online-course/', "Cold & World's Soups" => '/product/cold-and-world-soups-course-online-course/', "Hors d'Oeuvres Mastery" => '/product/hors-doeuvres-mastery-and-canapes-online-course/', 'Restaurant Mindset and Strategy' => '/product/restaurant-mindset-and-strategy-online-course/', 'Business Planning for Restaurants' => '/product/restaurant-business-planning-online-course/', ]; if ( isset( $course_urls[ $course_name ] ) ) { return home_url( $course_urls[ $course_name ] ); } // Fallback only reached for a course name outside the confirmed list. $slug = strtolower( $course_name ); $slug = str_replace( '&', 'and', $slug ); $slug = preg_replace( "/['']/", '', $slug ); $slug = preg_replace( '/[^a-z0-9\s-]/', '', $slug ); $slug = preg_replace( '/\s+/', '-', trim( $slug ) ); return home_url( '/product/' . $slug . '-online-course/' ); } $promo_course_title = ''; if ( $promo_course_id ) { $title = get_the_title( $promo_course_id ); if ( in_array( $title, $confirmed_courses, true ) ) { $promo_course_title = $title; } } // ─── CONTENT-BASED COURSE DETECTION ──────────────────── // Scans the recipe's actual title, ingredients, and instructions for keyword // signals and maps to the most relevant of the 18 confirmed courses. // This works immediately, before OCRS meal_type tagging is complete, // because it reads what the recipe actually IS, not a taxonomy field. function ocs_detect_course_from_content( $title, $ingredients, $instructions, $confirmed_courses ) { $title_text = strtolower( $title ); $ingredient_text = ''; if ( ! empty( $ingredients ) ) { foreach ( $ingredients as $ing ) { $ingredient_text .= ' ' . strtolower( $ing['name'] ?? '' ); } } $instruction_text = ''; if ( ! empty( $instructions ) ) { foreach ( $instructions as $inst ) { $instruction_text .= ' ' . strtolower( wp_strip_all_tags( $inst['text'] ?? '' ) ); } } // Ordered keyword → course map. First match wins, so more specific // signals are listed before broader ones. $signal_map = [ // Hors d'oeuvres / appetizers — checked early since these often // contain a protein or vegetable keyword that would otherwise // misroute to a different course (e.g. "Crab Canapés" should // go to Hors d'Oeuvres, not get lost in a seafood-soup match) '/\b(canape|hors d.oeuvre|amuse.bouche|bruschetta|crostini)\b/' => "Hors d'Oeuvres Mastery", // Knife / cutting technique signals '/\b(julienne|brunoise|chiffonade|finely chop)\b/' => 'Professional Vegetable Cuts', '/\b(carrot|celery|leek|shallot|onion|zucchini|vegetable)\b.*\b(chop|cut|slice|dice)\b/' => 'Knife Skills & Vegetable Cuts', '/\b(knife|fillet|debone|carving)\b/' => 'Knife Skills & Basic Cuts', // Stocks '/\bwhite stock\b/' => 'White Stocks Making', '/\bbrown stock\b/' => 'Brown Stocks Making', '/\bvegetable stock\b/' => 'Vegetable Stocks Making', '/\b(stock|bouillon|broth)\b/' => 'Stock Making Fundamentals', // Soups '/\b(seafood|fish|crab|lobster|shrimp|prawn)\b.*\bsoup\b/' => 'Seafood Soups Mastery', '/\b(consomme|clear soup|bouillon clair)\b/' => 'Clear Soups Mastery', '/\b(chilled|cold|gazpacho)\b.*\bsoup\b/' => "Cold & World's Soups", '/\bsoup\b/' => 'Soups Making 101', // Safety / handling '/\b(food safety|sanitation|haccp)\b/' => 'Food Safety Course 101', '/\b(food handler)\b/' => 'Food Handler Certificate', // Equipment '/\b(equipment|mandoline|immersion blender|stand mixer)\b/' => 'Kitchen Equipment Basics', // Business / restaurant '/\b(restaurant|menu pricing|food cost|labour cost|business plan)\b/' => 'Restaurant Mindset and Strategy', ]; // Title checked first, alone — this is the most reliable signal of what the dish IS foreach ( $signal_map as $pattern => $course ) { if ( in_array( $course, $confirmed_courses, true ) && preg_match( $pattern, $title_text ) ) { return $course; } } // Then ingredients foreach ( $signal_map as $pattern => $course ) { if ( in_array( $course, $confirmed_courses, true ) && preg_match( $pattern, $ingredient_text ) ) { return $course; } } // Then instructions, last resort foreach ( $signal_map as $pattern => $course ) { if ( in_array( $course, $confirmed_courses, true ) && preg_match( $pattern, $instruction_text ) ) { return $course; } } return ''; } $detected_course_title = ocs_detect_course_from_content( get_the_title( $post_id ), $ingredients, $instructions, $confirmed_courses ); $course_title_to_link = $promo_course_title ?: $detected_course_title; $course_url = $course_title_to_link ? ocs_course_url( $course_title_to_link ) : ''; // Point 3: dynamic counts — always reflect current database, never hardcoded $ocs_total_recipes = wp_count_posts( 'ocs_recipe' )->publish; $ocs_site_stats = class_exists( 'OCRS_Learning_Site' ) ? OCRS_Learning_Site::stats() : array(); $ocs_total_courses = isset( $ocs_site_stats['courses'] ) ? $ocs_site_stats['courses'] : count( $confirmed_courses ); $ocs_total_lessons = isset( $ocs_site_stats['lessons'] ) ? $ocs_site_stats['lessons'] : 1249; $has_image = has_post_thumbnail( $post_id ); $image_url = $has_image ? get_the_post_thumbnail_url( $post_id, 'large' ) : ''; $image_alt = $has_image ? get_post_meta( get_post_thumbnail_id( $post_id ), '_wp_attachment_image_alt', true ) : get_the_title(); $has_video = ! empty( $youtube_id ); $related_recipes = []; if ( $cuisines && ! is_wp_error( $cuisines ) ) { $related_query = new WP_Query( [ 'post_type' => 'ocs_recipe', 'posts_per_page' => 3, 'post__not_in' => [ $post_id ], 'orderby' => 'rand', 'tax_query' => [ [ 'taxonomy' => 'recipe_cuisine', 'field' => 'term_id', 'terms' => wp_list_pluck( $cuisines, 'term_id' ) ] ], ] ); if ( $related_query->have_posts() ) { $related_recipes = $related_query->posts; } wp_reset_postdata(); } $linked_product_ids = get_post_meta( $post_id, '_recipe_products', true ) ?: []; $tools_used = []; if ( ! empty( $linked_product_ids ) && is_array( $linked_product_ids ) ) { foreach ( $linked_product_ids as $pid ) { $title = get_the_title( $pid ); if ( $title ) { $tools_used[] = [ 'label' => $title, 'brand' => get_post_meta( $pid, '_product_brand', true ), 'url' => get_post_meta( $pid, '_product_affiliate_url', true ) ]; } } } $tools_is_placeholder = empty( $tools_used ); if ( $tools_is_placeholder ) { $tools_used = [ [ 'label' => 'Immersion Blender', 'brand' => 'KitchenAid', 'url' => '' ], [ 'label' => "8\" Chef's Knife", 'brand' => 'Victorinox', 'url' => '' ], [ 'label' => 'Heavy-Bottom Stock Pot', 'brand' => 'All-Clad', 'url' => '' ], ]; } // ─── MERGED CHEF'S NOTE — detected from actual recipe content ── function ocs_generate_chefs_note( $title, $ingredients, $instructions ) { $title_lower = strtolower( $title ); $ingredient_text = ''; if ( ! empty( $ingredients ) ) { foreach ( $ingredients as $ing ) { $ingredient_text .= ' ' . strtolower( $ing['name'] ?? '' ); } } $instruction_text = ''; if ( ! empty( $instructions ) ) { foreach ( $instructions as $inst ) { $instruction_text .= ' ' . strtolower( wp_strip_all_tags( $inst['text'] ?? '' ) ); } } // Title checked FIRST and on its own — the title names the actual dish, // so it must win over generic words anywhere in instructions. // Ordered most-specific to least-specific. $signals = [ // Named star ingredients — most specific, checked first '/\bwalnut/' => "Walnuts go from toasted to burnt in seconds — keep a close eye on them and pull them the moment they're fragrant.", '/\bhazelnut/' => "Toast hazelnuts just until the skins start to crack and you can smell them — any longer and they turn bitter.", '/\balmond/' => "Watch almonds closely as they toast — their high oil content means they can burn fast once they start to color.", '/\bpecan/' => "Pecans scorch quickly — toast them over moderate heat and remove them the second they smell nutty.", '/\bendive/' => "Belgian endive turns bitter if it's overcooked or browned too hard — braise it gently and keep the color pale.", '/\basparagus/' => "Don't overcook asparagus — it should still have a slight bite and bright color when it comes off the heat.", '/\bcrab/' => "Crab is delicate — handle it gently and add it at the last moment so the texture stays intact, not shredded.", '/\blobster/' => "Lobster meat toughens fast with overcooking — pull it just as it turns opaque and finish off the heat.", '/\bshrimp|\bprawn/' => "Shrimp cook in minutes — watch for the curl and the color change, then get them off the heat immediately.", '/\bscallop/' => "Scallops need a hot, dry pan and patience — let them sear undisturbed to get a real crust before you flip.", '/\bsalmon/' => "Salmon is forgiving but still easy to overcook — aim for just-opaque in the center and a little translucent at the very core.", '/\btuna/' => "Tuna is best seared hot and fast, leaving the center rare — overcooking dries it out quickly.", '/\boyster/' => "Keep oysters well chilled until the moment you serve or cook them — temperature control is everything for safety and texture.", '/\bduck/' => "Render duck fat slowly over low heat before searing — that patience is what gives you crisp skin without burning it.", '/\bfoie gras/' => "Foie gras melts fast in a hot pan — sear it hard and quick, just a minute or two per side.", '/\blamb/' => "Let lamb rest after cooking — a few quiet minutes off the heat lets the juices settle back into the meat.", '/\bveal/' => "Veal is lean and cooks quickly — watch it closely so it doesn't dry out.", '/\bchorizo/' => "Render chorizo slowly first to release its paprika oil — that oil becomes the base of flavor for the rest of the dish.", '/\bgarlic/' => "Garlic burns fast and turns bitter — add it after the onions have softened, not at the start.", '/\bonion/' => "Take your time caramelizing onions — rushing with high heat gives you color without the real depth of sweetness.", '/\bmushroom/' => "Don't crowd mushrooms in the pan — too many at once and they steam instead of browning.", '/\bcheese/' => "Let cheese come to room temperature before serving or melting for the best texture and flavor.", '/\bchocolate/' => "Melt chocolate gently and never let any water touch it — even a drop can cause it to seize.", '/\begg/' => "Watch your eggs closely near the end — a few extra seconds is the difference between silky and overcooked.", // Technique/dish-type signals — checked after named ingredients '/\bsoup\b/' => "The secret to a silky soup like this one is patience at the blending stage — take your time and pass it through a fine sieve if you want a truly professional finish.", '/\b(stock|bouillon|broth)\b/' => "Skim often and never let a stock boil hard — a gentle simmer is what keeps it clear and full of flavor.", '/\b(sauce|reduction|deglaz)\b/' => "A great sauce is built on reduction, not shortcuts — let it come down slowly and taste as you go; that's where the depth of flavor really develops.", '/\b(cake|pastry|dough|tart|creme brulee)\b/' => "Precision matters more in pastry than almost anywhere else in the kitchen — measure carefully and don't rush the resting times.", '/\bsalad\b/' => "A good salad lives or dies on the dressing balance — start light on the acid, taste, then adjust.", '/\b(julienne|brunoise|chiffonade)\b/' => "Good knife work isn't about speed, it's about consistency — even cuts cook evenly, and that's where flavor and presentation both come from.", '/\b(canape|hors d.oeuvre|tartare)\b/' => "With small bites like this one, balance is everything — every element should be tasted in a single, deliberate bite.", '/\b(steak|roast|grilled)\b/' => "Let your protein rest after cooking — a few quiet minutes off the heat makes all the difference to the texture.", ]; $title_text = $title_lower; foreach ( $signals as $pattern => $note ) { if ( preg_match( $pattern, $title_text ) ) { return $note; } } // No title match — check ingredients next (the actual content of the dish) foreach ( $signals as $pattern => $note ) { if ( preg_match( $pattern, $ingredient_text ) ) { return $note; } } // Last resort: instructions foreach ( $signals as $pattern => $note ) { if ( preg_match( $pattern, $instruction_text ) ) { return $note; } } return "Taste as you build this dish and adjust the seasoning at each stage — that habit alone will improve almost anything you cook."; } // Detect corrupted WPRM Slate.js rich-text JSON or raw HTML leaking into chef_notes. // If detected, discard it entirely and fall back to the auto-generated technique note // rather than ever risking garbage output on a live page. function ocs_chef_notes_is_corrupted( $text ) { if ( empty( $text ) ) return false; $corruption_markers = [ 'data-slate-', 'fragment=', '

', '

', '

Bouquet Garni: Classic French Herb Bundle for Stocks & Sauces

Prep5 min
Total5 min
Yield1 Bouquet Garni
LevelBeginner
 
 
About This Recipe

Learn how to make a bouquet garni, the classic French bundle of parsley stems, thyme and bay leaf used to flavour stocks, soups, sauces and braises. Includes tying and removal tips.

Scale This Recipe

Servings

Ingredients

Units
  • 5 sprigs Parsley,
  • 3 sprigs Fresh thyme
  • 10 whole Black
  • 1 large Bay leaf
  • 1 small — green part only

Instructions

  1. 1

    Place the bay leaf, thyme, parsley, and celery on one piece of green leek. Cover with the remaining piece of green leek. Tie securely with fine string, leaving a length of string attached so that the can be easily retrieved.

Take It Further

Master the techniques behind this dish

This recipe is one of 320 in the OCS library — structured into 38 courses through the OCRS™ learning system. Pick a course and learn the technique behind it.

Tools Used in This Recipe

KitchenAid
Immersion Blender
Victorinox
8" Chef's Knife
All-Clad
Heavy-Bottom Stock Pot
Chef's Notes

Taste as you build this dish and adjust the seasoning at each stage — that habit alone will improve almost anything you cook. You'll find techniques like this one across our full course library.

If you'd ever like hands-on guidance for your own kitchen or restaurant, I also offer 1-on-1 coaching through OCS, or you can reach me directly for consulting at 911ChefEric.com.

— Chef Eric

Ready to cook like a professional?

38 structured courses. 320 recipes. OCRS™ learning paths. Certificates. Coaching.

Keep learning

Learn the technique behind the recipe.

Recipes come out right when you understand the method. Chef Eric’s courses teach the foundations step by step — knife skills, stocks, soups and classic French technique — with video lessons and short quizzes. Not sure where to start? OCRS™ will build your roadmap in five questions.