Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
},
"metadata": {
"description": "Claude skills for Dynamicweb 10 — organized by task domain, bundled by role.",
"version": "5.8.6"
"version": "5.8.7"
},
"plugins": [
{
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
All notable changes to the Dynamicweb Skills plugin are recorded here. The
`version` field in `.claude-plugin/marketplace.json` tracks these entries.

## [5.8.7]

- **`dw-render-viewmodels` `viewmodel-traps.md`: the "no picture" fallback hides a null
`DefaultImage`.** With `Ecom/Picture/NoPicture` set, an image-less product renders the fallback image
and an unguarded template never fails, so a crash reproduction or a sweep proof must blank the
fallback for the run. The fallback also covers unguarded templates until they are fixed.

## [5.8.6]

- **`dw-demo-fo` `Get-FoErrorText` is safe under strict mode.** A 404 with no response body (no
Expand Down
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"version": 2,
"generatedAt": "2026-10-02T08:59:15.942Z",
"generatedAt": "2026-10-02T09:00:35.927Z",
"worksOn": {
"dw": {
"ring": "R1",
Expand Down
16 changes: 16 additions & 0 deletions skills/dw-render-viewmodels/references/viewmodel-traps.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,22 @@ string imagePath = product?.DefaultImage?.Value ?? string.Empty;
| `product.ReplacementProduct` | no replacement is configured on a discontinued product | `p?.ReplacementProduct?.…` |
| `Model.Item` | the paragraph has no item attached | `Model.Item?.GetString("Field")` |

**`DefaultImage` is null only when the ecommerce "no picture" fallback is empty too.** When the
`Ecom/Picture/NoPicture` setting in `GlobalSettings.Ecom.config` (`Large` and `Large_path`) names an
image, DW fills `product.DefaultImage` with it for a product with no image and no assets. The page then
renders that fallback image, and an unguarded template never meets the null. That cuts both ways:

- **Reproducing a crash, or proving a sweep catches one:** an image-less product is not enough. Blank
`NoPicture` `Large` and `Large_path` for the run, recycle the app pool, and restore both afterwards.
With the fallback set, an unguarded `Swift-v2_ProductMedia.cshtml` rendered a clean PDP for
a zero-asset product; with it blank, the same PDP rendered a `NullReferenceException` block at HTTP 200
[dw 10.28.12 · swift 2.4].
- **Running templates that still lack the guard:** setting the global fallback image keeps image-less
products from crashing them until the templates are fixed. It hides the data gap, so it does not
replace the guard.

Not measured: whether a `Medium` or `Small` fallback alone has the same effect.

Two shipped Swift 2.2 templates dereference `product.DefaultImage.Value` with no guard and are worth
auditing on any solution running them, because each turns one image-less product into a whole dead
surface:
Expand Down
Loading