README file from
GithubWeekly Meal Shopper
Plan a week of meals on an Obsidian canvas, keep recipe amounts in consistent metric measures, and generate a categorised shopping list from that plan.
The plugin ships with its own starter templates. You do not need Obsidian's Templates core plugin.
Support the project: Buy Me a Coffee
First start
- Open
Settings → Weekly Meal Shopper. - Under Setup → Templates, click
Run setupand choose where the editable canvas and recipe templates should live. - Under Setup → Files and folders, set your recipe folder, meal plan canvas and shopping list note.
- Run
Open or create meal plan canvas, then add recipe cards to it. - Run
Generate weekly shopping list from meal-plan canvas.
Commands
Thirteen commands cover the everyday work. One-off and bulk actions live in settings instead, so the command palette stays short.
| Command | What it does |
|---|---|
| Open recipe view in current tab | Split ingredients/directions reading view |
| Open recipe card (planning view) | Recipe card modal, with add-to-canvas |
| Create recipe note from template | New blank recipe note |
| Transcribe recipe from URL entry (website/YouTube) | Imports a recipe from a link |
| Standardise current recipe (preview) | Shows the proposed changes for this note before writing |
| Calculate recipe macros | Per-serving energy and macros for this note |
| Open or create meal plan canvas | Opens the configured canvas, creating it if needed |
| Set active canvas as meal plan canvas | Asks whether this is the primary or second canvas |
| Add active recipe to meal plan | Asks whether it's a weekly meal, a project or hosting |
| Generate weekly shopping list from meal-plan canvas | Builds the shopping list |
| Apply frozen leftovers from meal-plan canvas | As above, and updates frozen portions |
| Manage frozen portions inventory | Edit frozen portions per recipe |
| Add ingredient override from current shopping list line | Recategorise an item from the list itself |
In settings: standardise all recipes, restore a backup, check recipes for problems, calculate macros for every recipe, transcribe an image folder, re-download the nutrition dataset, set a nutrition match, and manage frozen portions.
Settings
Seven groups, in the order you meet them:
- Setup — recipe folder, canvas, shopping list note, and the one-off template setup.
- Recipes & import — metadata field, recipe card view, transcription and your OpenAI key.
- Measurements & rounding — cup sizes, weight-first conversion, the stored ingredient line, which ingredients keep spoons, and unit aliases.
- Shopping list — categories, exclusions, overrides, dried legumes, pack sizes and pantry-check measures.
- Meal-plan canvas — household size, week start, the canvas panels, and a second prep session.
- Nutrition — macro tracking, energy unit, dataset and manual matches.
- Data & maintenance — bulk actions. Nothing is written until you confirm.
How amounts are stored
Ingredients live in the ### Ingredients section in four slots: Amount ; Unit ; Ingredient ; Preparation. Blank slots stay empty, so 1; ; sweet potato; roughly chopped is one sweet potato, no unit, roughly chopped. The separator is configurable (;, ,, :, |). The body is the source of truth; the IngredientsParsed frontmatter field mirrors it and is refreshed automatically a couple of seconds after you edit a note.
Amounts are metric-first:
- Grams wherever a density is known, including liquids, because that's what you cook with.
- Spoons for ingredients where a gram weight is useless: extracts, leavening, and all ground and dried spices by default. You can pin more ingredients to spoons in settings. Anything under 2 g becomes a spoon measure or a pinch.
- Fresh herbs measured by volume keep their tbsp or cup, because density estimates for loose leaves are unreliable.
- A site's own metric values win. If a recipe page publishes 200 g of chocolate chips, that's what's stored — never a converted cup.
Rounding: grams and millilitres to 1 below 10, 5 up to 100, then 10; teaspoons to ¼, tablespoons to ½, cups to ¼; counts to ½, or ¼ below 1. Values a recipe's author wrote are never rounded, and amounts under ¼ cup are stored in tablespoons rather than rounded up.
IngredientsParsed also records where each amount came from (site-metric, dual-unit, converted or original) and keeps the exact unrounded value.
Importing recipes
Transcribe recipe from URL entry fetches the page itself:
- WP Recipe Maker and Tasty Recipes sites: the plugin reads the metric amounts the site publishes.
- Any page with standard recipe structured data: ingredients and steps are taken as written, and OpenAI is not called at all.
- Instagram: the caption is read from the page's description metadata. This needs the plugin's own user agent, so the fetch sends one.
- Anything else, and all image transcription, uses OpenAI with your own API key.
- Mediavine Create is not supported — it's untested, so it falls back to the generic path.
Imported ingredients are shown for review before the note is written, with a badge showing where each amount came from.
Standardise
Standardise current recipe (preview) and Data & maintenance → Standardise all recipes run the same thing: a preview of every proposed line, before → after, grouped into ready, needs review and skipped. You choose what gets written.
- Directions are never rewritten. The only changes are removing bold the plugin previously added and normalising oven temperatures to
180°C (160°C fan). - Legacy free-text ingredients are converted locally, including splitting lines that hold several ingredients. Anything it can't split confidently is flagged rather than guessed.
- A note with headings outside the standard sections is skipped, so nothing is lost.
- Every write is backed up first to
.obsidian/plugins/weekly-meal-shopper/backups/(the last 5 runs). Restore them from settings. - A written note gets
MeasurementsVerified: truein its frontmatter and is skipped by later runs.
Shopping lists
Totals are aggregated unrounded across the plan, then each line is written as what you'd actually pick up:
- Counts are whole and keep what they count:
(21 slices) bread, not21 breads. - Packs: bunches, bags, loaves and cans come from
pack-sizes.json, with what the recipes use alongside —(1 loaf) bread — recipes use 21 slices. The built-in sizes are typical Australian supermarket estimates and are editable in settings. - Liquids are shown in ml and L, which is easier to picture in a shop, even though recipes store them in grams.
- Pantry check: categories you choose get a second measure, e.g.
(600 g, ≈ 4¾ cups) plain flour. - Needs attention: recipes with blank or unreadable
Portionsare listed at the top, because a blank one is counted as a single portion. A recipe whose ingredients can't be read is flagged there too instead of stopping the list.
Canvas panels
- Meal Coverage — per recipe, whether one cook covers what you've planned, with an icon and a word rather than a colour alone, plus buttons for the shopping list and frozen portions. Cards are coloured to match. Click a row to acknowledge one you're happy to cook again.
- Macro Details — per-day energy with a protein/carbs/fat bar, and a button to calculate any meals that don't have macros yet.
Macros and nutrition
- Turn on macro tracking, then run
Calculate recipe macros. Per-serving figures are cached to frontmatter and written into the note's### Nutritionsection. - Names are matched against a curated per-100g table, the downloaded USDA dataset, cached live lookups and your own overrides, in increasing priority.
- Matching tolerates brand and packaging words ("Cube Meredith Dairy feta" → feta cheese) but a name must account for at least half of the entry it matches, so plain "bread" never resolves to bread flour.
- Nothing is guessed. Anything unresolved is listed under the table; an ingredient with no set amount ("salt, to taste") is reported as excluded, not missing.
Configuration files
Created in the plugin folder on first use, and editable:
| File | Holds |
|---|---|
ingredient-categories.json |
Shopping category rules |
unit-density-rules.json |
Grams per ml per ingredient. Layered over the built-in table; 0 switches one off |
unit-aliases.json |
Extra unit spellings |
pack-sizes.json |
How things are sold: bunches, bags, loaves, cans |
nutrition-*.json |
Nutrition dataset, live-lookup cache and manual matches |
Network use, AI and privacy
Planning, parsing, standardising and shopping lists all work offline.
- Recipe pages are fetched directly when you import a URL, including Instagram, which needs the plugin's own user agent.
- OpenAI (
api.openai.com) is used only for image transcription and for pages with no structured recipe data, with your own API key stored in this vault'sdata.json. Standardising never sends your directions anywhere. - Nutrition (off by default): turning on macro tracking downloads USDA Foundation Foods once (
fdc.nal.usda.gov, desktop only). The optional live-lookup fallback queries USDA (api.nal.usda.gov, your own free key) or Open Food Facts (world.openfoodfacts.org) for ingredients not found locally, and caches every result.
No telemetry, no ads.
Recipe view
- Split-pane reading view in the current tab.
- Left: ingredients from parsed metadata, click to cross off. Right: directions with a step focus box and
j/knavigation. - Ingredients mentioned in the active step are highlighted as you read. That highlighting is applied at display time and never written into the note.
Supported image formats for folder transcription: jpg/jpeg, png, webp, gif, bmp, heic/heif, tif/tiff, avif.