A while back, I built a meal planner in Google Sheets. It scores recipes by how many ingredients you already have, generates a grocery list, and pushes it to Google Tasks or Apple Reminders. I wrote about the full build in "How to Build a Meal Planner and Grocery List Automation with Google Sheets." If you want the whole system, start there.

This article is about one problem a subscriber reached out with. "Is there an easy way to add sheets and change the script to the sheets added? For example, if I wanted Mains on one sheet and Soups on another sheet?" I love this idea. I don't eat multiple courses during dinner, but I can see where this would be really useful for hosting holidays or events.

A small change fixes that. After the update, the meal planner can pull from any number of tabs: Mains, Soups, Baking, Weeknight, Date Night, etc. You won't need to reconfigure anything else.

How the Meal Planner Works

Quick background, the planner lives in a Google Sheet with two types of tabs:

Recipe Tabs

Each row is a recipe with four columns: Name, Ingredients, Steps, and This Week. The This Week The column is a checkbox on what you’re cooking this Week. 

Pantry Tabs

One tab that tracks what you have on hand, with Item, In Stock, and Quantity columns.

A Google Apps Script reads both tabs and scores each recipe by how many ingredients are missing from the pantry. The recipes get ranked by the number of missing ingredients and then surfaced through Google Tasks or Apple Shortcuts. 

The full setup — including the sidebar UI, Apple Shortcuts, and web app deployment — is covered in the original article.

The Problem: One Hardcoded Tab Name

The function that reads recipes is called getAllRecipes(). In the original version, it looks like this:

function getAllRecipes(ss) {
  var sheet = ss.getSheetByName("Recipes")
  var data = sheet.getDataRange().getValues()
  var recipes = []
  for (var i = 1; i < data.length; i++) {
    if (!data[i][0]) continue
    recipes.push({
      name: String(data[i][0]).trim(),
      ingredients: String(data[i][1] || "").trim(),
      steps: String(data[i][2] || "").trim(),
      thisWeek: data[i][3] === true,
    })
  }
  return recipes
}

getSheetByName("Recipes") — that's the constraint. Rename the tab or add a second one, and the script either fails silently or ignores it entirely.

The Fix: Loop All The Sheets, Skip Pantry

Instead of asking for a specific sheet by name, the updated version asks for all sheets, then skips any sheet named Pantry and any sheet with no data:

function getAllRecipes(ss) {
  var sheets = ss.getSheets()
  var recipes = []

  for (var s = 0; s < sheets.length; s++) {
    var sheet = sheets[s]
    var name = sheet.getName()

    // Skip the Pantry tab — it's not a recipe sheet
    if (name === "Pantry") continue

    var data = sheet.getDataRange().getValues()

    // Skip sheets with no data rows (only a header, or completely empty)
    if (data.length <= 1) continue

    for (var i = 1; i < data.length; i++) {
      if (!data[i][0]) continue
      recipes.push({
        name: String(data[i][0]).trim(),
        ingredients: String(data[i][1] || "").trim(),
        steps: String(data[i][2] || "").trim(),
        thisWeek: data[i][3] === true,
      })
    }
  }

  return recipes
}

The function returns the same shape as before — an array of recipe objects. Everything else in the script (scoring, grocery list generation, Cook Tonight, pantry deduction, and the Apple Shortcuts web app) continues to work without any changes.

Setting up the sheet

If you’re starting fresh, here’s what to build:

Recipe Tabs

Create one tab per category. Name them whatever you want: Mains, Soups, Baking, Quick Dinners. Each tab needs the same four columns in the same order.

  • Ingredients: comma-separated list with quantities

  • Steps: each step on its own line

  • This Week: always a checkbox (Insert -> Checkbox). The script looks for true/false this column.

Pantry Tab

One tab named exactly Pantry with three columns. Item, In Stock(Checkbox), Quantity. The script uses this to score recipes and dedupe ingredients after cooking.

How to Add it to an Existing Sheet

If you already have the original grocery automation running, the update is a two-minute swap:

  1. Open your Google Sheet → Extensions → Apps Script

  2. Find the existing getAllRecipes function

  3. Select it entirely (from function getAllRecipes(ss) { to its closing })

  4. Paste in the new version above.

  5. Save (Cmd+S / Ctrl+S)

  6. Deploy → Manage Deployments → edit your existing deployment → set version to New version → Deploy

Then, rename your existing Recipes tab to whatever category fits (Mains, Dinners, etc.) and add new tabs as needed. The script picks them all up on the next run. Apple Shortcuts don't need any changes.

Gotchas

Pantry is a reserved name

The script skips any sheet named Pantry. Don't name a recipe tab Pantry — it will be silently ignored.

Column structure must match across all tabs.

Each recipe tab needs the same four columns in the same order. If a tab has a different structure, the script reads the wrong columns without throwing an error — recipe names will look garbled, and ingredients won't parse correctly.

Column D needs checkboxes on every tab

The thisWeek flag reads true only from a checked checkbox cell. If you add a new tab and forget the checkboxes, those recipes will never appear in the This Week list.

Blank or notes tabs are fine.

Any tab with no data in rows 2 and beyond is skipped. So scratch tabs and notes tabs are safe — as long as column A is empty.

Tabs with data in column A get read as recipe sheets

If you have any other tab with text in column A (e.g., a budget tracker or a shopping history), the script will try to read it as recipes. Either rename it or keep column A clear.

Want the Template?

I put together a Google Sheets template with two recipe tabs (Mains and Soups) pre-populated with sample recipes, the Pantry tab, and the updated script already attached.

Keep Reading