Skip to content

Instantly share code, notes, and snippets.

@patrickbolle
Last active August 31, 2026 21:20
Show Gist options
  • Select an option

  • Save patrickbolle/32ee120eb48568f19a10c80f9c2984a6 to your computer and use it in GitHub Desktop.

Select an option

Save patrickbolle/32ee120eb48568f19a10c80f9c2984a6 to your computer and use it in GitHub Desktop.
RecipeKit Svelte widget manual install snippet (auto-synced)
{% comment %}RecipeKit Svelte Widget v1.13.2{% endcomment %}
{%- assign rk_settings = shop.metafields.recipekit.settings -%}
{%- if rk_settings.settings.default_heading_type == 'h2' -%}{%- assign rk_heading_tag = 'h2' -%}{%- else -%}{%- assign rk_heading_tag = 'h1' -%}{%- endif -%}
{%- assign rk_lang = shop.metafields.recipekit.rk_lang -%}
{%- assign rk_recipe_id = blank -%}
{%- assign rk_mf = blank -%}
{%- comment -%}A recipe hangs off an article or a store page: same metafield, keyed by the resource id. Pages have no author or publish date, so the JSON-LD falls back to the shop and to the recipe's own date.{%- endcomment -%}
{%- if article -%}{%- assign rk_src = article -%}{%- elsif page -%}{%- assign rk_src = page -%}{%- endif -%}
{%- assign rk_src_url = rk_src.url -%}
{%- assign rk_src_author = rk_src.author | default: shop.name -%}
{%- assign rk_src_date = rk_src.published_at -%}
{%- if rk_src -%}
{%- assign rk_resource_id = rk_src.id | downcase -%}
{%- assign rk_type = rk_src.metafields.recipekit[rk_resource_id].type -%}
{%- if rk_type == 'json' -%}
{%- assign rk_mf = rk_src.metafields.recipekit[rk_resource_id].value -%}
{%- else -%}
{%- assign rk_mf = rk_src.metafields.recipekit[rk_resource_id] -%}
{%- endif -%}
{%- if rk_mf != blank -%}
{%- assign rk_recipe_id = rk_mf.recipe_id -%}
{%- endif -%}
{%- endif -%}
{%- comment -%}Shopify hands back a json metafield as a plain string in any locale that has a translation registered against it, and a Translate & Adapt pass over a post picks the recipe field up. `rk_mf.recipe_id` then reads as nothing and the card vanishes on that locale alone. Recover the id from the raw string so the widget still renders and fetches its own data. rk_mf is cleared because neither the fallback card nor the JSON-LD can be built out of a string. A non-numeric scrape is dropped rather than passed on: the widget shows an error for an unusable id, which is worse than the blank space this replaces.{%- endcomment -%}
{%- if rk_recipe_id == blank and rk_mf != blank -%}
{%- assign rk_mf_str = rk_mf | append: '' -%}
{%- if rk_mf_str contains '"recipe_id"' -%}
{%- assign rk_mf_parts = rk_mf_str | split: '"recipe_id":' -%}
{%- assign rk_scraped_id = rk_mf_parts[1] | split: ',' | first | remove: '"' | remove: '}' | strip -%}
{%- assign rk_scraped_num = rk_scraped_id | times: 1 -%}
{%- if rk_scraped_num > 0 -%}{%- assign rk_recipe_id = rk_scraped_num -%}{%- endif -%}
{%- endif -%}
{%- assign rk_mf = '' -%}
{%- endif -%}
{%- if rk_recipe_id != blank -%}
{%- if rk_mf != blank -%}
<script type="application/json" id="recipe-data-{{ rk_recipe_id }}">{{ rk_mf | json }}</script>
{%- assign rk_rc = rk_mf.rating_count | default: '1' | at_least: '1' -%}
{%- assign rk_rv = rk_mf.recipe_rating | ceil | default: 5 | at_most: 5 -%}
{%- if rk_rv == 0 -%}{%- assign rk_rv = 5 -%}{%- endif -%}
{%- comment -%}recipe_video may hold a full embed snippet, not a URL. Take the FIRST src (Vimeo and TikTok paste a trailing loader script tag, so the last src is the wrong URL) and drop anything still containing markup: raw HTML in the JSON-LD breaks the whole block, since its quotes close the string early.{%- endcomment -%}
{%- assign rk_ld_video = rk_mf.recipe_video -%}
{%- if rk_ld_video contains 'src="' -%}{%- assign rk_ld_video_parts = rk_ld_video | split: 'src="' -%}{%- assign rk_ld_video = rk_ld_video_parts[1] | split: '"' | first -%}{%- elsif rk_ld_video contains "src='" -%}{%- assign rk_ld_video_parts = rk_ld_video | split: "src='" -%}{%- assign rk_ld_video = rk_ld_video_parts[1] | split: "'" | first -%}{%- endif -%}
{%- if rk_ld_video contains '<' -%}{%- assign rk_ld_video = '' -%}{%- endif -%}
{%- capture rk_ld_i -%}{%- for i in rk_mf.recipe_ingredients -%}{%- unless i.type == 'heading' -%},{{ i.ingredient | strip_html | json }}{%- endunless -%}{%- endfor -%}{%- endcapture -%}
{%- capture rk_ld_d -%}{%- for d in rk_mf.recipe_directions -%}{%- unless d.type == 'heading' -%},{"@type":"HowToStep","text":{{ d.direction | strip_html | json }},"name":{{ d.step_name | default: d.direction | strip_html | json }},"url":"{{ shop.url }}{{ rk_src_url }}#step-{{- forloop.index -}}"{%- if d.image != blank -%}{%- assign rk_step_img = d.image | replace: 'https://f000.backblazeb2.com/file/recipekit-bucket/', 'https://images.getrecipekit.com/' -%}{%- if rk_step_img contains '?' -%}{%- assign rk_step_img = rk_step_img | append: '&width=700' -%}{%- else -%}{%- assign rk_step_img = rk_step_img | append: '?width=700' -%}{%- endif -%},"image":{{ rk_step_img | json }}{%- endif -%}}{%- endunless -%}{%- endfor -%}{%- endcapture -%}
{%- comment -%}contentUrl/embedUrl are normalized server side (TikTok and Instagram are stored as embed HTML, which Liquid cannot parse). Recipes saved before that shipped fall back to the old host check on the raw value.{%- endcomment -%}
{%- assign rk_video_content = rk_mf.video_content_url -%}
{%- assign rk_video_embed = rk_mf.video_embed_url -%}
{%- if rk_video_content == blank and rk_ld_video != blank -%}{%- if rk_ld_video contains 'youtube' or rk_ld_video contains 'youtu.be' or rk_ld_video contains 'shorts' or rk_ld_video contains 'vimeo' -%}{%- assign rk_video_content = rk_ld_video -%}{%- endif -%}{%- endif -%}
{%- comment -%}uploadDate is the video's publish date. A merchant-entered date keeps its calendar value: running it through the date filter would shift it a day in shops west of UTC. Both branches get a midnight-UTC time appended because Google warns on a bare date for VideoObject.uploadDate ("missing a time zone"); Z is used rather than the shop offset so historical dates need no DST guess.{%- endcomment -%}
{%- if rk_mf.video_upload_date != blank -%}{%- assign rk_upload_date = rk_mf.video_upload_date | append: 'T00:00:00Z' -%}{%- else -%}{%- assign rk_upload_date = rk_src_date | default: rk_mf.recipe_date | date: '%Y-%m-%d' | append: 'T00:00:00Z' -%}{%- endif -%}
{% assign rk_ld_attr = 'type="application/ld+json"' %}<script {{ rk_ld_attr }}>{"@context":"https://schema.org/","@type":"Recipe","name":{{ rk_mf.recipe_title | strip_html | json }}{%- if rk_mf.recipe_image != blank -%}{%- comment -%}Recipe images are stored as raw Backblaze B2 URLs. Served direct they bypass the CDN and burn the bucket's download cap (outage 2026-08-07); images.getrecipekit.com is the BunnyCDN pull zone over the same bucket, prefix stripped. Rewritten at each use site rather than via a shared assign so no branch can render an unrewritten URL.{%- endcomment -%},"image":[{{ rk_mf.recipe_image | replace: 'https://f000.backblazeb2.com/file/recipekit-bucket/', 'https://images.getrecipekit.com/' | json }}]{%- endif -%},"description":{{ rk_mf.recipe_description | strip_html | json }}{%- if rk_mf.recipe_tags.size > 0 -%},"keywords":[{%- for keyword in rk_mf.recipe_tags -%}{{ keyword.name | default: keyword | strip_html | json }}{%- unless forloop.last -%},{%- endunless -%}{%- endfor -%}]{%- endif -%},"author":{"@type":"Person","name":{{ rk_mf.recipe_author | strip_html | default: rk_src_author | json }}},"datePublished":"{{- rk_mf.recipe_date | default: rk_src_date | date: '%Y-%m-%d' -}}"{%- if rk_mf.iso_prep_time != blank -%},"prepTime":"{{- rk_mf.iso_prep_time -}}"{%- endif -%}{%- if rk_mf.iso_cook_time != blank -%},"cookTime":"{{- rk_mf.iso_cook_time -}}"{%- endif -%}{%- if rk_mf.iso_total_time != blank -%},"totalTime":"{{- rk_mf.iso_total_time -}}"{%- endif -%}{%- if rk_mf.serving_size != blank -%},"recipeYield":{{ rk_mf.serving_size | strip_html | json }}{%- endif -%}{%- if rk_mf.recipe_category != blank -%},"recipeCategory":{{ rk_mf.recipe_category | strip_html | json }}{%- endif -%}{%- if rk_mf.recipe_cuisine != blank -%},"recipeCuisine":{{ rk_mf.recipe_cuisine | strip_html | json }}{%- endif -%},"recipeIngredient":[{{- rk_ld_i | remove_first: ',' -}}],"recipeInstructions":[{{- rk_ld_d | remove_first: ',' -}}],"nutrition":{"@type":"NutritionInformation"{%- if rk_mf.nutrition_serving_size != blank -%},"servingSize":{{ rk_mf.nutrition_serving_size | strip_html | json }}{%- endif -%}{%- if rk_mf.recipe_calories != blank -%},"calories":"{{- rk_mf.recipe_calories -}}"{%- endif -%}{%- for nutrition_field in rk_mf.nutrition_data -%}{%- unless nutrition_field.value == blank or nutrition_field.value == 'calories' or nutrition_field.dynamic == true -%},{{ nutrition_field.value | json }}:{{ nutrition_field.content | append: '' | json }}{%- endunless -%}{%- endfor -%}}{%- if rk_rc > 0 and rk_mf.enable_rating == true or rk_mf.enable_rating == 'true' -%},"aggregateRating":{"@type":"AggregateRating","ratingValue":{{- rk_rv | default: 5 -}},"bestRating":5,"worstRating":1,"ratingCount":{{- rk_rc | default: 1 -}}}{%- endif -%}{%- if rk_video_content != blank -%},"video":{"@type":"VideoObject","name":{{ rk_mf.recipe_title | strip_html | json }},"description":{{ rk_mf.recipe_description | strip_html | json }}{%- if rk_mf.recipe_image != blank -%},"thumbnailUrl":{{ rk_mf.recipe_image | replace: 'https://f000.backblazeb2.com/file/recipekit-bucket/', 'https://images.getrecipekit.com/' | json }}{%- endif -%},"contentUrl":{{ rk_video_content | json }}{%- if rk_video_embed != blank -%},"embedUrl":{{ rk_video_embed | json }}{%- endif -%},"uploadDate":"{{- rk_upload_date -}}"}{%- endif -%}}</script>
{%- endif -%}
{%- if rk_settings.settings.enable_servings_adjuster == false -%}
{%- assign rk_enable_servings_adjuster = false -%}
{%- else -%}
{%- assign rk_enable_servings_adjuster = true -%}
{%- endif -%}
{%- comment -%}Border defaults to on. Cannot use `| default: true` here: Liquid treats false as blank and would flip it back on.{%- endcomment -%}
{%- if rk_settings.design_border == false -%}
{%- assign rk_design_border = false -%}
{%- else -%}
{%- assign rk_design_border = true -%}
{%- endif -%}
{%- comment -%}The card CSS is no longer inlined into the bundle, so link it here. It is render-blocking, which is the point: the fallback below is a real card at first paint instead of raw text that reflows once the JS lands. The pre-hydration rules that used to sit in an inline <style> now live in this file too.{%- endcomment -%}
<link rel="stylesheet" href="https://widget.recipekit.com/widget/v2/templates/recipekit-widget.css">
{%- comment -%}Preload, not <script src>: the guarded loader below stops a second copy of this snippet double-registering the custom element, and this still lets the preload scanner start the fetch.{%- endcomment -%}
<link rel="preload" as="script" href="https://widget.recipekit.com/widget/v2/templates/recipekit-widget.js">
<recipe-kit
recipeid="{{ rk_recipe_id }}"
shop="{{ shop.permanent_domain }}"
design="{{ rk_settings.recipe_design | default: 'rk_uptown' }}"
color="{{ rk_settings.design_colour | default: '#000000' }}"
designborder="{{ rk_design_border }}"
enableatc="{{ rk_settings.enable_atc | default: false }}"
enableallatc="{{ rk_settings.enable_all_atc | default: false }}"
enableclicktocheck="{{ rk_settings.click_to_check | default: false }}"
enablecookmode="{{ rk_settings.settings.cook_mode_enabled | default: false }}"
clicktoconfirmrating="{{ rk_settings.settings.click_to_confirm_rating | default: false }}"
enableservingsadjuster="{{ rk_enable_servings_adjuster }}"
servingsaboveingredients="{{ rk_settings.settings.servings_above_ingredients | default: false }}"
showqtystepper="{{ rk_settings.settings.show_qty_stepper | default: false }}"
showingredientthumbnails="{{ rk_settings.settings.show_ingredient_thumbnails | default: false }}"
enableunittoggle="{{ rk_settings.settings.enable_unit_toggle | default: false }}"
apiurl="{{ rk_lang.app_url | default: 'https://app.getrecipekit.com' }}"
headingtag="{{ rk_heading_tag }}"
>{%- if rk_mf != blank -%}
{%- comment -%}
Fallback card. Carries the same class names the Svelte templates render, so the
stylesheet linked above paints it as the real card at first paint and hydration is
a visual no-op. The widget removes it in onMount; it also serves scrapers, AI bots
and no-JS visitors.
{%- endcomment -%}
{%- assign rk_fb_design = rk_settings.recipe_design | default: 'rk_uptown' -%}
{%- if rk_fb_design == 'rk_modern_vertical' -%}
{%- assign rk_fb_class = 'rk_modern rk_modern_vertical' -%}
{%- elsif rk_fb_design contains 'rk_modern' -%}
{%- assign rk_fb_class = 'rk_modern rk_modern_column' -%}
{%- else -%}
{%- assign rk_fb_class = rk_fb_design -%}
{%- endif -%}
{%- comment -%}Uptown and Modern Vertical are the two designs whose templates pass rk_section_header.{%- endcomment -%}
{%- if rk_fb_design == 'rk_uptown' or rk_fb_design == 'rk_modern_vertical' -%}
{%- assign rk_fb_heading = 'rk_column_heading rk_section_header' -%}
{%- else -%}
{%- assign rk_fb_heading = 'rk_column_heading' -%}
{%- endif -%}
{%- capture rk_fb_img -%}{%- if rk_mf.recipe_image != blank -%}{%- assign rk_img = rk_mf.recipe_image | replace: 'https://f000.backblazeb2.com/file/recipekit-bucket/', 'https://images.getrecipekit.com/' -%}{%- if rk_img contains 'images.getrecipekit.com' -%}{%- unless rk_img contains '?' -%}{%- assign rk_img = rk_img | append: '?width=1200&quality=90' -%}{%- endunless -%}{%- endif -%}<img src="{{ rk_img }}" alt="{{ rk_mf.recipe_title | escape }}">{%- endif -%}{%- endcapture -%}
{%- comment -%}Meta cells come from parallel key/value lists: cheaper than repeating the cell markup, and blank values are skipped, which is how the cuisine/author swap works. Editorial shows cuisine in its own eyebrow label and author in the strip; every other design does the reverse.{%- endcomment -%}
{%- capture rk_fb_keys -%}{{ rk_settings.rk_lang_serving | default: 'Servings' }}~|~{{ rk_settings.rk_lang_prep_time | default: 'Prep Time' }}~|~{{ rk_settings.rk_lang_cook_time | default: 'Cook Time' }}~|~{{ rk_settings.rk_lang_calories | default: 'Calories' }}~|~{{ rk_settings.rk_lang.cuisine | default: 'Cuisine' }}~|~{{ rk_settings.rk_lang_category | default: 'Category' }}~|~{{ rk_settings.rk_lang_author | default: 'Author' }}{%- endcapture -%}
{%- capture rk_fb_values -%}{{ rk_mf.serving_size }}~|~{{ rk_mf.prep_time }}~|~{{ rk_mf.cook_time }}~|~{{ rk_mf.recipe_calories }}~|~{%- unless rk_fb_design == 'rk_editorial' -%}{{ rk_mf.recipe_cuisine }}{%- endunless -%}~|~{{ rk_mf.recipe_category }}~|~{%- if rk_fb_design == 'rk_editorial' -%}{{ rk_mf.recipe_author }}{%- endif -%}{%- endcapture -%}
{%- assign rk_fb_key_list = rk_fb_keys | split: '~|~' -%}
{%- assign rk_fb_value_list = rk_fb_values | split: '~|~' -%}
{%- capture rk_fb_meta -%}<div class="rk_grid">{%- for k in rk_fb_key_list -%}{%- assign v = rk_fb_value_list[forloop.index0] -%}{%- if v != blank -%}<div class="rk_column"><div class="rk_meta">{{ k }}</div><p>{{ v }}</p></div>{%- endif -%}{%- endfor -%}</div>{%- endcapture -%}
{%- capture rk_fb_desc -%}{%- if rk_mf.recipe_description != blank -%}<div class="rk_description">{{ rk_mf.recipe_description }}</div>{%- endif -%}{%- endcapture -%}
{%- comment -%}Group headings close and reopen the list, matching the widget's grouped markup. An empty <ul>/<ol> at either end is hidden by a :empty rule in the stylesheet.{%- endcomment -%}
{%- capture rk_fb_ingredients -%}{%- if rk_mf.recipe_ingredients != blank -%}<div class="rk_ingredients rk_column"><div class="rk_ingredients_header"><h2 class="{{ rk_fb_heading }}"><span>{{ rk_settings.rk_lang_ingredients | default: 'Ingredients' }}</span></h2></div><ul>{%- for i in rk_mf.recipe_ingredients -%}{%- if i.type == 'heading' -%}</ul><h3 class="rk_group_heading">{{ i.ingredient | strip_html }}</h3><ul>{%- else -%}<li><span class="rk_ingredient_content">{{ i.ingredient }}</span></li>{%- endif -%}{%- endfor -%}</ul></div>{%- endif -%}{%- endcapture -%}
{%- capture rk_fb_directions -%}{%- if rk_mf.recipe_directions != blank -%}<div class="rk_directions rk_column"><h2 class="{{ rk_fb_heading }}"><span>{{ rk_settings.rk_lang_directions | default: 'Directions' }}</span></h2><ol>{%- for d in rk_mf.recipe_directions -%}{%- if d.type == 'heading' -%}</ol><h3 class="rk_group_heading">{{ d.direction | strip_html }}</h3><ol>{%- else -%}<li><div class="rk_direction_content">{{ d.direction }}</div></li>{%- endif -%}{%- endfor -%}</ol></div>{%- endif -%}{%- endcapture -%}
<div class="recipekit-fallback" id="rk_parent" style="--design-colour:{{ rk_settings.design_colour | default: '#000000' }}"><div class="{{ rk_fb_class }}"><div class="rk_container{% unless rk_design_border %} rk_no_border{% endunless %}"><div class="rk_card">{%- if rk_fb_design == 'rk_editorial' -%}{%- if rk_fb_img != blank -%}<div class="rk_hero">{{ rk_fb_img }}</div>{%- endif -%}<div class="rk_header">{%- if rk_mf.recipe_cuisine != blank -%}<div class="rk_cuisine_label">{{ rk_mf.recipe_cuisine }}</div>{%- endif -%}<{{ rk_heading_tag }} class="rk_heading">{{ rk_mf.recipe_title }}</{{ rk_heading_tag }}>{{ rk_fb_desc }}{{ rk_fb_meta }}</div><div class="rk_body rk_two_col"><div class="rk_sidebar rk_sidebar_ingredients">{{ rk_fb_ingredients }}</div><section class="rk_main_col">{{ rk_fb_directions }}</section></div>{%- else -%}<div class="rk_header">{%- if rk_fb_design == 'rk_uptown' and rk_fb_img != blank -%}<div class="rk_column rk_image">{{ rk_fb_img }}</div>{%- endif -%}<div class="rk_grid"><div class="rk_column rk_primary"><{{ rk_heading_tag }} class="rk_heading">{{ rk_mf.recipe_title }}</{{ rk_heading_tag }}>{%- if rk_mf.recipe_author != blank -%}<div class="rk_subheading">{{ rk_mf.recipe_author }}</div>{%- endif -%}</div></div><div class="rk_grid rk_secondary"><div class="rk_column rk_details{% if rk_mf.recipe_image != blank %} rk_has_image{% endif %}">{{ rk_fb_meta }}<div>{{ rk_fb_desc }}</div></div>{%- if rk_fb_design != 'rk_uptown' and rk_fb_img != blank -%}<div class="rk_column rk_image">{{ rk_fb_img }}</div>{%- endif -%}</div></div>{%- if rk_fb_class contains 'rk_modern_column' -%}<div class="rk_body rk_grid"><div class="rk_column rk_column_third">{{ rk_fb_ingredients }}</div><div class="rk_column">{{ rk_fb_directions }}</div></div>{%- else -%}<div class="rk_body">{{ rk_fb_ingredients }}{{ rk_fb_directions }}</div>{%- endif -%}{%- endif -%}</div></div></div></div>
{%- endif -%}</recipe-kit>
<script>
if (!window.recipeKitSvelteLoaded) {
var s = document.createElement('script');
s.src = 'https://widget.recipekit.com/widget/v2/templates/recipekit-widget.js';
s.async = true;
document.head.appendChild(s);
window.recipeKitSvelteLoaded = true;
}
</script>
{%- endif -%}
{% comment %}RecipeKit Svelte Widget v1.1.1{% endcomment %}
{%- assign rk_settings = shop.metafields.recipekit.settings -%}
{%- assign rk_lang = shop.metafields.recipekit.rk_lang -%}
{%- assign rk_recipe_id = blank -%}
{%- assign rk_mf = blank -%}
{%- if article -%}
{%- assign rk_resource_id = article.id | downcase -%}
{%- assign rk_type = article.metafields.recipekit[rk_resource_id].type -%}
{%- if rk_type == 'json' -%}
{%- assign rk_mf = article.metafields.recipekit[rk_resource_id].value -%}
{%- else -%}
{%- assign rk_mf = article.metafields.recipekit[rk_resource_id] -%}
{%- endif -%}
{%- if rk_mf != blank -%}
{%- assign rk_recipe_id = rk_mf.recipe_id -%}
{%- endif -%}
{%- endif -%}
{%- if rk_recipe_id != blank -%}
{%- if rk_mf != blank -%}
<script type="application/json" id="recipe-data-{{ rk_recipe_id }}">{{ rk_mf | json }}</script>
{%- assign rk_rc = rk_mf.rating_count | default: '1' | at_least: '1' -%}
{%- assign rk_rv = rk_mf.recipe_rating | ceil | default: 5 | at_most: 5 -%}
{%- if rk_rv == 0 -%}{%- assign rk_rv = 5 -%}{%- endif -%}
{%- capture rk_ld_i -%}{%- for i in rk_mf.recipe_ingredients -%}{%- unless i.type == 'heading'
-%},"{{- i.ingredient | strip_html | escape -}}"{%- endunless -%}{%- endfor -%}{%- endcapture -%}
{%- capture rk_ld_d -%}{%- for d in rk_mf.recipe_directions -%}{%- unless d.type == 'heading'
-%},{"@type":"HowToStep","text":"{{- d.direction | strip_html | escape -}}","name":"{{- d.step_name |
default: d.direction | strip_html | escape -}}","url":"{{ shop.url }}{{ article.url }}#step-{{-
forloop.index -}}"{%- if d.image != blank -%},"image":"{{- d.image | replace:
'https://f000.backblazeb2.com/file/recipekit-bucket/', 'https://images.getrecipekit.com/' | append:
'?width=700' -}}"{%- endif -%}}{%- endunless -%}{%- endfor -%}{%- endcapture -%}
{% assign rk_ld_attr = 'type="application/ld+json"' %}<script {{ rk_ld_attr
}}>{"@context":"https://schema.org/","@type":"Recipe","name":"{{- rk_mf.recipe_title | escape
-}}","image":["{{- rk_mf.recipe_image -}}"],"description":"{{- rk_mf.recipe_description | strip_html |
escape -}}","keywords":[{%- for keyword in rk_mf.recipe_tags -%}"{{- keyword.name | escape -}}"{%-
unless forloop.last -%},{%- endunless -%}{%- endfor -%}],"author":{"@type":"Person","name":"{{-
rk_mf.recipe_author | strip_html | escape | default: article.author -}}"},"datePublished":"{{-
rk_mf.recipe_date | default: article.published_at | date: '%Y-%m-%d' -}}","prepTime":"{{-
rk_mf.iso_prep_time -}}","cookTime":"{{- rk_mf.iso_cook_time -}}","totalTime":"{{- rk_mf.iso_total_time
-}}","recipeYield":"{{- rk_mf.serving_size | escape -}}","recipeCategory":"{{- rk_mf.recipe_category |
escape -}}","recipeCuisine":"{{- rk_mf.recipe_cuisine | strip_html | escape
-}}","recipeIngredient":[{{- rk_ld_i | remove_first: ',' -}}],"recipeInstructions":[{{- rk_ld_d |
remove_first: ',' -}}],"nutrition":{"@type":"NutritionInformation","servingSize":"{{-
rk_mf.serving_size | escape -}}"{%- if rk_mf.recipe_calories != blank -%},"calories":"{{-
rk_mf.recipe_calories -}}"{%- endif -%}}{%- if rk_rc > 0 and rk_mf.enable_rating == true or
rk_mf.enable_rating == 'true' -%},"aggregateRating":{"@type":"AggregateRating","ratingValue":"{{- rk_rv
| default: '5' -}}","bestRating":"5","worstRating":"1","ratingCount":"{{- rk_rc | default: '1'
-}}"}{%- endif -%}{%- if rk_mf.recipe_video != blank and rk_mf.recipe_video contains 'youtube' or
rk_mf.recipe_video contains 'shorts' or rk_mf.recipe_video contains 'youtu.be' or rk_mf.recipe_video
contains 'vimeo' -%},"video":{"@type":"VideoObject","name":"{{- rk_mf.recipe_title | escape
-}}","description":"{{- rk_mf.recipe_description | strip_html | escape -}}","thumbnailUrl":"{{-
rk_mf.recipe_image -}}","contentUrl":"{{- rk_mf.recipe_video -}}","uploadDate":"{{- rk_mf.recipe_date
-}}"}{%- endif -%}}</script>
{%- endif -%}
{%- comment -%}
Widget-feature toggles default to the shop-level setting (configured on the
admin Settings page). Merchants using the app block can override these
per placement in their theme editor.
{%- endcomment -%}
{%- if rk_settings.settings.enable_servings_adjuster == false -%}
{%- assign rk_enable_servings_adjuster = false -%}
{%- else -%}
{%- assign rk_enable_servings_adjuster = true -%}
{%- endif -%}
<recipe-kit
recipeid="{{ rk_recipe_id }}"
shop="{{ shop.permanent_domain }}"
design="{{ rk_settings.recipe_design | default: 'rk_uptown' }}"
color="{{ rk_settings.design_colour | default: '#000000' }}"
enableatc="{{ rk_settings.enable_atc | default: false }}"
enableclicktocheck="{{ rk_settings.click_to_check | default: false }}"
enablecookmode="{{ rk_settings.settings.cook_mode_enabled | default: false }}"
clicktoconfirmrating="{{ rk_settings.settings.click_to_confirm_rating | default: false }}"
enableservingsadjuster="{{ rk_enable_servings_adjuster }}"
servingsaboveingredients="{{ rk_settings.settings.servings_above_ingredients | default: false }}"
showqtystepper="{{ rk_settings.settings.show_qty_stepper | default: false }}"
apiurl="{{ rk_lang.app_url | default: 'https://app.getrecipekit.com' }}"
></recipe-kit>
<script>
if (!window.recipeKitSvelteLoaded) {
var s = document.createElement('script');
s.src = 'https://widget.recipekit.com/widget/v2/templates/recipekit-widget.js';
s.async = true;
document.head.appendChild(s);
window.recipeKitSvelteLoaded = true;
}
</script>
{%- endif -%}
{%- assign rk_settings = shop.metafields.recipekit.settings -%}
{%- assign rk_lang = shop.metafields.recipekit.rk_lang -%}
{%- assign rk_recipe_id = blank -%}
{%- assign rk_mf = blank -%}
{%- if article -%}
{%- assign rk_resource_id = article.id | downcase -%}
{%- assign rk_type = article.metafields.recipekit[rk_resource_id].type -%}
{%- if rk_type == 'json' -%}
{%- assign rk_mf = article.metafields.recipekit[rk_resource_id].value -%}
{%- else -%}
{%- assign rk_mf = article.metafields.recipekit[rk_resource_id] -%}
{%- endif -%}
{%- if rk_mf != blank -%}
{%- assign rk_recipe_id = rk_mf.recipe_id -%}
{%- endif -%}
{%- endif -%}
{%- if rk_recipe_id != blank -%}
{%- if rk_mf != blank -%}
<script type="application/json" id="recipe-data-{{ rk_recipe_id }}">{{ rk_mf | json }}</script>
{%- assign rk_rc = rk_mf.rating_count | default: '1' | at_least: '1' -%}
{%- assign rk_rv = rk_mf.recipe_rating | ceil | default: 5 | at_most: 5 -%}
{%- if rk_rv == 0 -%}{%- assign rk_rv = 5 -%}{%- endif -%}
{%- capture rk_ld_i -%}{%- for i in rk_mf.recipe_ingredients -%}{%- unless i.type == 'heading'
-%},"{{- i.ingredient | strip_html | escape -}}"{%- endunless -%}{%- endfor -%}{%- endcapture -%}
{%- capture rk_ld_d -%}{%- for d in rk_mf.recipe_directions -%}{%- unless d.type == 'heading'
-%},{"@type":"HowToStep","text":"{{- d.direction | strip_html | escape -}}","name":"{{- d.step_name |
default: d.direction | strip_html | escape -}}","url":"{{ shop.url }}{{ article.url }}#step-{{-
forloop.index -}}"{%- if d.image != blank -%},"image":"{{- d.image | replace:
'https://f000.backblazeb2.com/file/recipekit-bucket/', 'https://images.getrecipekit.com/' | append:
'?width=700' -}}"{%- endif -%}}{%- endunless -%}{%- endfor -%}{%- endcapture -%}
{% assign rk_ld_attr = 'type="application/ld+json"' %}<script {{ rk_ld_attr
}}>{"@context":"https://schema.org/","@type":"Recipe","name":"{{- rk_mf.recipe_title | escape
-}}","image":["{{- rk_mf.recipe_image -}}"],"description":"{{- rk_mf.recipe_description | strip_html |
escape -}}","keywords":[{%- for keyword in rk_mf.recipe_tags -%}"{{- keyword.name | escape -}}"{%-
unless forloop.last -%},{%- endunless -%}{%- endfor -%}],"author":{"@type":"Person","name":"{{-
rk_mf.recipe_author | strip_html | escape | default: article.author -}}"},"datePublished":"{{-
rk_mf.recipe_date | default: article.published_at | date: '%Y-%m-%d' -}}","prepTime":"{{-
rk_mf.iso_prep_time -}}","cookTime":"{{- rk_mf.iso_cook_time -}}","totalTime":"{{- rk_mf.iso_total_time
-}}","recipeYield":"{{- rk_mf.serving_size | escape -}}","recipeCategory":"{{- rk_mf.recipe_category |
escape -}}","recipeCuisine":"{{- rk_mf.recipe_cuisine | strip_html | escape
-}}","recipeIngredient":[{{- rk_ld_i | remove_first: ',' -}}],"recipeInstructions":[{{- rk_ld_d |
remove_first: ',' -}}],"nutrition":{"@type":"NutritionInformation","servingSize":"{{-
rk_mf.serving_size | escape -}}"{%- if rk_mf.recipe_calories != blank -%},"calories":"{{-
rk_mf.recipe_calories -}}"{%- endif -%}}{%- if rk_rc > 0 and rk_mf.enable_rating == true or
rk_mf.enable_rating == 'true' -%},"aggregateRating":{"@type":"AggregateRating","ratingValue":"{{- rk_rv
| default: '5' -}}","bestRating":"5","worstRating":"1","ratingCount":"{{- rk_rc | default: '1'
-}}"}{%- endif -%}{%- if rk_mf.recipe_video != blank and rk_mf.recipe_video contains 'youtube' or
rk_mf.recipe_video contains 'shorts' or rk_mf.recipe_video contains 'youtu.be' or rk_mf.recipe_video
contains 'vimeo' -%},"video":{"@type":"VideoObject","name":"{{- rk_mf.recipe_title | escape
-}}","description":"{{- rk_mf.recipe_description | strip_html | escape -}}","thumbnailUrl":"{{-
rk_mf.recipe_image -}}","contentUrl":"{{- rk_mf.recipe_video -}}","uploadDate":"{{- rk_mf.recipe_date
-}}"}{%- endif -%}}</script>
{%- endif -%}
<recipe-kit
recipeid="{{ rk_recipe_id }}"
shop="{{ shop.permanent_domain }}"
design="{{ rk_settings.recipe_design | default: 'rk_uptown' }}"
color="{{ rk_settings.design_colour | default: '#000000' }}"
enableatc="{{ rk_settings.enable_atc | default: false }}"
enableclicktocheck="{{ rk_settings.click_to_check | default: false }}"
enablecookmode="{{ rk_settings.settings.cook_mode_enabled | default: false }}"
clicktoconfirmrating="{{ rk_settings.settings.click_to_confirm_rating | default: false }}"
apiurl="{{ rk_lang.app_url | default: 'https://app.getrecipekit.com' }}"
></recipe-kit>
<script>
if (!window.recipeKitSvelteLoaded) {
var s = document.createElement('script');
s.src = 'https://widget.recipekit.com/widget/v2/templates/recipekit-widget.js';
s.async = true;
document.head.appendChild(s);
window.recipeKitSvelteLoaded = true;
}
</script>
{%- endif -%}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment