shopify-starter-kit 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agent/skills/shopify-apps/SKILL.md +47 -0
- package/.agent/skills/shopify-automation/SKILL.md +172 -0
- package/.agent/skills/shopify-development/README.md +60 -0
- package/.agent/skills/shopify-development/SKILL.md +368 -0
- package/.agent/skills/shopify-development/references/app-development.md +578 -0
- package/.agent/skills/shopify-development/references/extensions.md +555 -0
- package/.agent/skills/shopify-development/references/themes.md +498 -0
- package/.agent/skills/shopify-development/scripts/requirements.txt +19 -0
- package/.agent/skills/shopify-development/scripts/shopify_graphql.py +428 -0
- package/.agent/skills/shopify-development/scripts/shopify_init.py +441 -0
- package/.agent/skills/shopify-development/scripts/tests/test_shopify_init.py +379 -0
- package/bin/cli.js +3 -0
- package/package.json +32 -0
- package/src/index.js +116 -0
- package/templates/.agent/skills/shopify-apps/SKILL.md +47 -0
- package/templates/.agent/skills/shopify-automation/SKILL.md +172 -0
- package/templates/.agent/skills/shopify-development/README.md +60 -0
- package/templates/.agent/skills/shopify-development/SKILL.md +368 -0
- package/templates/.agent/skills/shopify-development/references/app-development.md +578 -0
- package/templates/.agent/skills/shopify-development/references/extensions.md +555 -0
- package/templates/.agent/skills/shopify-development/references/themes.md +498 -0
- package/templates/.agent/skills/shopify-development/scripts/requirements.txt +19 -0
- package/templates/.agent/skills/shopify-development/scripts/shopify_graphql.py +428 -0
- package/templates/.agent/skills/shopify-development/scripts/shopify_init.py +441 -0
- package/templates/.agent/skills/shopify-development/scripts/tests/test_shopify_init.py +379 -0
- package/templates/.devcontainer/devcontainer.json +27 -0
- package/templates/tests/playwright.config.ts +26 -0
- package/templates/tests/vitest.config.ts +9 -0
|
@@ -0,0 +1,498 @@
|
|
|
1
|
+
# Themes Reference
|
|
2
|
+
|
|
3
|
+
Guide for developing Shopify themes with Liquid templating.
|
|
4
|
+
|
|
5
|
+
## Liquid Templating
|
|
6
|
+
|
|
7
|
+
### Syntax Basics
|
|
8
|
+
|
|
9
|
+
**Objects (Output):**
|
|
10
|
+
```liquid
|
|
11
|
+
{{ product.title }}
|
|
12
|
+
{{ product.price | money }}
|
|
13
|
+
{{ customer.email }}
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
**Tags (Logic):**
|
|
17
|
+
```liquid
|
|
18
|
+
{% if product.available %}
|
|
19
|
+
<button>Add to Cart</button>
|
|
20
|
+
{% else %}
|
|
21
|
+
<p>Sold Out</p>
|
|
22
|
+
{% endif %}
|
|
23
|
+
|
|
24
|
+
{% for product in collection.products %}
|
|
25
|
+
{{ product.title }}
|
|
26
|
+
{% endfor %}
|
|
27
|
+
|
|
28
|
+
{% case product.type %}
|
|
29
|
+
{% when 'Clothing' %}
|
|
30
|
+
<span>Apparel</span>
|
|
31
|
+
{% when 'Shoes' %}
|
|
32
|
+
<span>Footwear</span>
|
|
33
|
+
{% else %}
|
|
34
|
+
<span>Other</span>
|
|
35
|
+
{% endcase %}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Filters (Transform):**
|
|
39
|
+
```liquid
|
|
40
|
+
{{ product.title | upcase }}
|
|
41
|
+
{{ product.price | money }}
|
|
42
|
+
{{ product.description | strip_html | truncate: 100 }}
|
|
43
|
+
{{ product.image | img_url: 'medium' }}
|
|
44
|
+
{{ 'now' | date: '%B %d, %Y' }}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Common Objects
|
|
48
|
+
|
|
49
|
+
**Product:**
|
|
50
|
+
```liquid
|
|
51
|
+
{{ product.id }}
|
|
52
|
+
{{ product.title }}
|
|
53
|
+
{{ product.handle }}
|
|
54
|
+
{{ product.description }}
|
|
55
|
+
{{ product.price }}
|
|
56
|
+
{{ product.compare_at_price }}
|
|
57
|
+
{{ product.available }}
|
|
58
|
+
{{ product.type }}
|
|
59
|
+
{{ product.vendor }}
|
|
60
|
+
{{ product.tags }}
|
|
61
|
+
{{ product.images }}
|
|
62
|
+
{{ product.variants }}
|
|
63
|
+
{{ product.featured_image }}
|
|
64
|
+
{{ product.url }}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**Collection:**
|
|
68
|
+
```liquid
|
|
69
|
+
{{ collection.title }}
|
|
70
|
+
{{ collection.handle }}
|
|
71
|
+
{{ collection.description }}
|
|
72
|
+
{{ collection.products }}
|
|
73
|
+
{{ collection.products_count }}
|
|
74
|
+
{{ collection.image }}
|
|
75
|
+
{{ collection.url }}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Cart:**
|
|
79
|
+
```liquid
|
|
80
|
+
{{ cart.item_count }}
|
|
81
|
+
{{ cart.total_price }}
|
|
82
|
+
{{ cart.items }}
|
|
83
|
+
{{ cart.note }}
|
|
84
|
+
{{ cart.attributes }}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**Customer:**
|
|
88
|
+
```liquid
|
|
89
|
+
{{ customer.email }}
|
|
90
|
+
{{ customer.first_name }}
|
|
91
|
+
{{ customer.last_name }}
|
|
92
|
+
{{ customer.orders_count }}
|
|
93
|
+
{{ customer.total_spent }}
|
|
94
|
+
{{ customer.addresses }}
|
|
95
|
+
{{ customer.default_address }}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**Shop:**
|
|
99
|
+
```liquid
|
|
100
|
+
{{ shop.name }}
|
|
101
|
+
{{ shop.email }}
|
|
102
|
+
{{ shop.domain }}
|
|
103
|
+
{{ shop.currency }}
|
|
104
|
+
{{ shop.money_format }}
|
|
105
|
+
{{ shop.enabled_payment_types }}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Common Filters
|
|
109
|
+
|
|
110
|
+
**String:**
|
|
111
|
+
- `upcase`, `downcase`, `capitalize`
|
|
112
|
+
- `strip_html`, `strip_newlines`
|
|
113
|
+
- `truncate: 100`, `truncatewords: 20`
|
|
114
|
+
- `replace: 'old', 'new'`
|
|
115
|
+
|
|
116
|
+
**Number:**
|
|
117
|
+
- `money` - Format currency
|
|
118
|
+
- `round`, `ceil`, `floor`
|
|
119
|
+
- `times`, `divided_by`, `plus`, `minus`
|
|
120
|
+
|
|
121
|
+
**Array:**
|
|
122
|
+
- `join: ', '`
|
|
123
|
+
- `first`, `last`
|
|
124
|
+
- `size`
|
|
125
|
+
- `map: 'property'`
|
|
126
|
+
- `where: 'property', 'value'`
|
|
127
|
+
|
|
128
|
+
**URL:**
|
|
129
|
+
- `img_url: 'size'` - Image URL
|
|
130
|
+
- `url_for_type`, `url_for_vendor`
|
|
131
|
+
- `link_to`, `link_to_type`
|
|
132
|
+
|
|
133
|
+
**Date:**
|
|
134
|
+
- `date: '%B %d, %Y'`
|
|
135
|
+
|
|
136
|
+
## Theme Architecture
|
|
137
|
+
|
|
138
|
+
### Directory Structure
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
theme/
|
|
142
|
+
├── assets/ # CSS, JS, images
|
|
143
|
+
├── config/ # Theme settings
|
|
144
|
+
│ ├── settings_schema.json
|
|
145
|
+
│ └── settings_data.json
|
|
146
|
+
├── layout/ # Base templates
|
|
147
|
+
│ └── theme.liquid
|
|
148
|
+
├── locales/ # Translations
|
|
149
|
+
│ └── en.default.json
|
|
150
|
+
├── sections/ # Reusable blocks
|
|
151
|
+
│ ├── header.liquid
|
|
152
|
+
│ ├── footer.liquid
|
|
153
|
+
│ └── product-grid.liquid
|
|
154
|
+
├── snippets/ # Small components
|
|
155
|
+
│ ├── product-card.liquid
|
|
156
|
+
│ └── icon.liquid
|
|
157
|
+
└── templates/ # Page templates
|
|
158
|
+
├── index.json
|
|
159
|
+
├── product.json
|
|
160
|
+
├── collection.json
|
|
161
|
+
└── cart.liquid
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Layout
|
|
165
|
+
|
|
166
|
+
Base template wrapping all pages (`layout/theme.liquid`):
|
|
167
|
+
|
|
168
|
+
```liquid
|
|
169
|
+
<!DOCTYPE html>
|
|
170
|
+
<html lang="{{ request.locale.iso_code }}">
|
|
171
|
+
<head>
|
|
172
|
+
<meta charset="utf-8">
|
|
173
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
174
|
+
<title>{{ page_title }}</title>
|
|
175
|
+
|
|
176
|
+
{{ content_for_header }}
|
|
177
|
+
|
|
178
|
+
<link rel="stylesheet" href="{{ 'theme.css' | asset_url }}">
|
|
179
|
+
</head>
|
|
180
|
+
<body>
|
|
181
|
+
{% section 'header' %}
|
|
182
|
+
|
|
183
|
+
<main>
|
|
184
|
+
{{ content_for_layout }}
|
|
185
|
+
</main>
|
|
186
|
+
|
|
187
|
+
{% section 'footer' %}
|
|
188
|
+
|
|
189
|
+
<script src="{{ 'theme.js' | asset_url }}"></script>
|
|
190
|
+
</body>
|
|
191
|
+
</html>
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Templates
|
|
195
|
+
|
|
196
|
+
Page-specific structures (`templates/product.json`):
|
|
197
|
+
|
|
198
|
+
```json
|
|
199
|
+
{
|
|
200
|
+
"sections": {
|
|
201
|
+
"main": {
|
|
202
|
+
"type": "product-template",
|
|
203
|
+
"settings": {
|
|
204
|
+
"show_vendor": true,
|
|
205
|
+
"show_quantity_selector": true
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
"recommendations": {
|
|
209
|
+
"type": "product-recommendations"
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
"order": ["main", "recommendations"]
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Legacy format (`templates/product.liquid`):
|
|
217
|
+
```liquid
|
|
218
|
+
<div class="product">
|
|
219
|
+
<div class="product-images">
|
|
220
|
+
<img src="{{ product.featured_image | img_url: 'large' }}" alt="{{ product.title }}">
|
|
221
|
+
</div>
|
|
222
|
+
|
|
223
|
+
<div class="product-details">
|
|
224
|
+
<h1>{{ product.title }}</h1>
|
|
225
|
+
<p class="price">{{ product.price | money }}</p>
|
|
226
|
+
|
|
227
|
+
{% form 'product', product %}
|
|
228
|
+
<select name="id">
|
|
229
|
+
{% for variant in product.variants %}
|
|
230
|
+
<option value="{{ variant.id }}">{{ variant.title }} - {{ variant.price | money }}</option>
|
|
231
|
+
{% endfor %}
|
|
232
|
+
</select>
|
|
233
|
+
|
|
234
|
+
<button type="submit">Add to Cart</button>
|
|
235
|
+
{% endform %}
|
|
236
|
+
</div>
|
|
237
|
+
</div>
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Sections
|
|
241
|
+
|
|
242
|
+
Reusable content blocks (`sections/product-grid.liquid`):
|
|
243
|
+
|
|
244
|
+
```liquid
|
|
245
|
+
<div class="product-grid">
|
|
246
|
+
{% for product in section.settings.collection.products %}
|
|
247
|
+
<div class="product-card">
|
|
248
|
+
<a href="{{ product.url }}">
|
|
249
|
+
<img src="{{ product.featured_image | img_url: 'medium' }}" alt="{{ product.title }}">
|
|
250
|
+
<h3>{{ product.title }}</h3>
|
|
251
|
+
<p>{{ product.price | money }}</p>
|
|
252
|
+
</a>
|
|
253
|
+
</div>
|
|
254
|
+
{% endfor %}
|
|
255
|
+
</div>
|
|
256
|
+
|
|
257
|
+
{% schema %}
|
|
258
|
+
{
|
|
259
|
+
"name": "Product Grid",
|
|
260
|
+
"settings": [
|
|
261
|
+
{
|
|
262
|
+
"type": "collection",
|
|
263
|
+
"id": "collection",
|
|
264
|
+
"label": "Collection"
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
"type": "range",
|
|
268
|
+
"id": "products_per_row",
|
|
269
|
+
"min": 2,
|
|
270
|
+
"max": 5,
|
|
271
|
+
"step": 1,
|
|
272
|
+
"default": 4,
|
|
273
|
+
"label": "Products per row"
|
|
274
|
+
}
|
|
275
|
+
],
|
|
276
|
+
"presets": [
|
|
277
|
+
{
|
|
278
|
+
"name": "Product Grid"
|
|
279
|
+
}
|
|
280
|
+
]
|
|
281
|
+
}
|
|
282
|
+
{% endschema %}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Snippets
|
|
286
|
+
|
|
287
|
+
Small reusable components (`snippets/product-card.liquid`):
|
|
288
|
+
|
|
289
|
+
```liquid
|
|
290
|
+
<div class="product-card">
|
|
291
|
+
<a href="{{ product.url }}">
|
|
292
|
+
{% if product.featured_image %}
|
|
293
|
+
<img src="{{ product.featured_image | img_url: 'medium' }}" alt="{{ product.title }}">
|
|
294
|
+
{% endif %}
|
|
295
|
+
<h3>{{ product.title }}</h3>
|
|
296
|
+
<p class="price">{{ product.price | money }}</p>
|
|
297
|
+
{% if product.compare_at_price > product.price %}
|
|
298
|
+
<p class="sale-price">{{ product.compare_at_price | money }}</p>
|
|
299
|
+
{% endif %}
|
|
300
|
+
</a>
|
|
301
|
+
</div>
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
Include snippet:
|
|
305
|
+
```liquid
|
|
306
|
+
{% render 'product-card', product: product %}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
## Development Workflow
|
|
310
|
+
|
|
311
|
+
### Setup
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
# Initialize new theme
|
|
315
|
+
shopify theme init
|
|
316
|
+
|
|
317
|
+
# Choose Dawn (reference theme) or blank
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### Local Development
|
|
321
|
+
|
|
322
|
+
```bash
|
|
323
|
+
# Start local server
|
|
324
|
+
shopify theme dev
|
|
325
|
+
|
|
326
|
+
# Preview at http://localhost:9292
|
|
327
|
+
# Changes auto-sync to development theme
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### Pull Theme
|
|
331
|
+
|
|
332
|
+
```bash
|
|
333
|
+
# Pull live theme
|
|
334
|
+
shopify theme pull --live
|
|
335
|
+
|
|
336
|
+
# Pull specific theme
|
|
337
|
+
shopify theme pull --theme=123456789
|
|
338
|
+
|
|
339
|
+
# Pull only templates
|
|
340
|
+
shopify theme pull --only=templates
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### Push Theme
|
|
344
|
+
|
|
345
|
+
```bash
|
|
346
|
+
# Push to development theme
|
|
347
|
+
shopify theme push --development
|
|
348
|
+
|
|
349
|
+
# Create new unpublished theme
|
|
350
|
+
shopify theme push --unpublished
|
|
351
|
+
|
|
352
|
+
# Push specific files
|
|
353
|
+
shopify theme push --only=sections,snippets
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### Theme Check
|
|
357
|
+
|
|
358
|
+
Lint theme code:
|
|
359
|
+
```bash
|
|
360
|
+
shopify theme check
|
|
361
|
+
shopify theme check --auto-correct
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
## Common Patterns
|
|
365
|
+
|
|
366
|
+
### Product Form with Variants
|
|
367
|
+
|
|
368
|
+
```liquid
|
|
369
|
+
{% form 'product', product %}
|
|
370
|
+
{% unless product.has_only_default_variant %}
|
|
371
|
+
{% for option in product.options_with_values %}
|
|
372
|
+
<div class="product-option">
|
|
373
|
+
<label>{{ option.name }}</label>
|
|
374
|
+
<select name="options[{{ option.name }}]">
|
|
375
|
+
{% for value in option.values %}
|
|
376
|
+
<option value="{{ value }}">{{ value }}</option>
|
|
377
|
+
{% endfor %}
|
|
378
|
+
</select>
|
|
379
|
+
</div>
|
|
380
|
+
{% endfor %}
|
|
381
|
+
{% endunless %}
|
|
382
|
+
|
|
383
|
+
<input type="hidden" name="id" value="{{ product.selected_or_first_available_variant.id }}">
|
|
384
|
+
<input type="number" name="quantity" value="1" min="1">
|
|
385
|
+
|
|
386
|
+
<button type="submit" {% unless product.available %}disabled{% endunless %}>
|
|
387
|
+
{% if product.available %}Add to Cart{% else %}Sold Out{% endif %}
|
|
388
|
+
</button>
|
|
389
|
+
{% endform %}
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
### Pagination
|
|
393
|
+
|
|
394
|
+
```liquid
|
|
395
|
+
{% paginate collection.products by 12 %}
|
|
396
|
+
{% for product in collection.products %}
|
|
397
|
+
{% render 'product-card', product: product %}
|
|
398
|
+
{% endfor %}
|
|
399
|
+
|
|
400
|
+
{% if paginate.pages > 1 %}
|
|
401
|
+
<div class="pagination">
|
|
402
|
+
{% if paginate.previous %}
|
|
403
|
+
<a href="{{ paginate.previous.url }}">Previous</a>
|
|
404
|
+
{% endif %}
|
|
405
|
+
|
|
406
|
+
{% for part in paginate.parts %}
|
|
407
|
+
{% if part.is_link %}
|
|
408
|
+
<a href="{{ part.url }}">{{ part.title }}</a>
|
|
409
|
+
{% else %}
|
|
410
|
+
<span class="current">{{ part.title }}</span>
|
|
411
|
+
{% endif %}
|
|
412
|
+
{% endfor %}
|
|
413
|
+
|
|
414
|
+
{% if paginate.next %}
|
|
415
|
+
<a href="{{ paginate.next.url }}">Next</a>
|
|
416
|
+
{% endif %}
|
|
417
|
+
</div>
|
|
418
|
+
{% endif %}
|
|
419
|
+
{% endpaginate %}
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
### Cart AJAX
|
|
423
|
+
|
|
424
|
+
```javascript
|
|
425
|
+
// Add to cart
|
|
426
|
+
fetch('/cart/add.js', {
|
|
427
|
+
method: 'POST',
|
|
428
|
+
headers: { 'Content-Type': 'application/json' },
|
|
429
|
+
body: JSON.stringify({
|
|
430
|
+
id: variantId,
|
|
431
|
+
quantity: 1
|
|
432
|
+
})
|
|
433
|
+
})
|
|
434
|
+
.then(res => res.json())
|
|
435
|
+
.then(item => console.log('Added:', item));
|
|
436
|
+
|
|
437
|
+
// Get cart
|
|
438
|
+
fetch('/cart.js')
|
|
439
|
+
.then(res => res.json())
|
|
440
|
+
.then(cart => console.log('Cart:', cart));
|
|
441
|
+
|
|
442
|
+
// Update cart
|
|
443
|
+
fetch('/cart/change.js', {
|
|
444
|
+
method: 'POST',
|
|
445
|
+
headers: { 'Content-Type': 'application/json' },
|
|
446
|
+
body: JSON.stringify({
|
|
447
|
+
id: lineItemKey,
|
|
448
|
+
quantity: 2
|
|
449
|
+
})
|
|
450
|
+
})
|
|
451
|
+
.then(res => res.json());
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
## Metafields in Themes
|
|
455
|
+
|
|
456
|
+
Access custom data:
|
|
457
|
+
|
|
458
|
+
```liquid
|
|
459
|
+
{{ product.metafields.custom.care_instructions }}
|
|
460
|
+
{{ product.metafields.custom.material.value }}
|
|
461
|
+
|
|
462
|
+
{% if product.metafields.custom.featured %}
|
|
463
|
+
<span class="badge">Featured</span>
|
|
464
|
+
{% endif %}
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
## Best Practices
|
|
468
|
+
|
|
469
|
+
**Performance:**
|
|
470
|
+
- Optimize images (use appropriate sizes)
|
|
471
|
+
- Minimize Liquid logic complexity
|
|
472
|
+
- Use lazy loading for images
|
|
473
|
+
- Defer non-critical JavaScript
|
|
474
|
+
|
|
475
|
+
**Accessibility:**
|
|
476
|
+
- Use semantic HTML
|
|
477
|
+
- Include alt text for images
|
|
478
|
+
- Support keyboard navigation
|
|
479
|
+
- Ensure sufficient color contrast
|
|
480
|
+
|
|
481
|
+
**SEO:**
|
|
482
|
+
- Use descriptive page titles
|
|
483
|
+
- Include meta descriptions
|
|
484
|
+
- Structure content with headings
|
|
485
|
+
- Implement schema markup
|
|
486
|
+
|
|
487
|
+
**Code Quality:**
|
|
488
|
+
- Follow Shopify theme guidelines
|
|
489
|
+
- Use consistent naming conventions
|
|
490
|
+
- Comment complex logic
|
|
491
|
+
- Keep sections focused and reusable
|
|
492
|
+
|
|
493
|
+
## Resources
|
|
494
|
+
|
|
495
|
+
- Theme Development: https://shopify.dev/docs/themes
|
|
496
|
+
- Liquid Reference: https://shopify.dev/docs/api/liquid
|
|
497
|
+
- Dawn Theme: https://github.com/Shopify/dawn
|
|
498
|
+
- Theme Check: https://shopify.dev/docs/themes/tools/theme-check
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Shopify Skill Dependencies
|
|
2
|
+
# Python 3.10+ required
|
|
3
|
+
|
|
4
|
+
# No Python package dependencies - uses only standard library
|
|
5
|
+
|
|
6
|
+
# Testing dependencies (dev)
|
|
7
|
+
pytest>=8.0.0
|
|
8
|
+
pytest-cov>=4.1.0
|
|
9
|
+
pytest-mock>=3.12.0
|
|
10
|
+
|
|
11
|
+
# Note: This script requires the Shopify CLI tool
|
|
12
|
+
# Install Shopify CLI:
|
|
13
|
+
# npm install -g @shopify/cli @shopify/theme
|
|
14
|
+
# or via Homebrew (macOS):
|
|
15
|
+
# brew tap shopify/shopify
|
|
16
|
+
# brew install shopify-cli
|
|
17
|
+
#
|
|
18
|
+
# Authenticate with:
|
|
19
|
+
# shopify auth login
|