Opened 7 weeks ago
Closed 6 weeks ago
#8270 closed defect (bug) (fixed)
Generated fallback SVG icons for plugins (geopattern-icon) are malformed
| Reported by: | slaFFik | Owned by: | dd32 |
|---|---|---|---|
| Priority: | normal | Milestone: | |
| Component: | Plugin Directory | Keywords: | has-patch |
| Cc: |
Description
Every auto-generated placeholder icon served from https://s.w.org/plugins/geopattern-icon/<slug>_<hex>.svg (the generic geometric icons created for plugins that have no custom icon) declares the viewBox attribute in all-lowercase (viewbox). SVG attribute names are case-sensitive, so this is an unrecognized attribute and the document effectively has no viewBox. As a result the SVG cannot be scaled correctly and fails to render in strict, spec-compliant SVG renderers — notably Apple's CoreSVG (the engine behind ImageIO and native iOS/macOS image loading). It renders as corrupted/garbled output.
The defect
Root element of cd-bp-avatar-bubble_6c6c6c.svg:
<svg xmlns="http://www.w3.org/2000/svg" width="60" height="60" viewbox="0 0 60 60" preserveAspectRatio="none">
The spec attribute is viewBox (camelCase) — see SVG 1.1 §7.7: https://www.w3.org/TR/SVG11/coords.html#ViewBoxAttribute
Because viewbox is not the real attribute, no user coordinate system is established. Any renderer drawing the icon at a size other than its intrinsic one (i.e. essentially every icon use case) has no way to map the internal coordinates to the requested pixel size, so output is clipped / mis-scaled / garbled.
Fix — a single casing change in the generator template:
<svg xmlns="http://www.w3.org/2000/svg" width="60" height="60" viewBox="0 0 60 60" preserveAspectRatio="none">
Why it has gone unnoticed
When an SVG is inlined into an HTML page, the HTML parser's foreign-content attribute-adjustment step auto-corrects viewbox → viewBox (it is listed in the HTML spec's SVG attribute adjustment table: https://html.spec.whatwg.org/multipage/parsing.html#creating-and-inserting-nodes), so it renders fine in a browser. But when the same file is fetched and parsed as a standalone image/svg+xml — via <img />, CSS background-image, or any native SVG image loader — no such correction happens, the viewBox is lost, and rendering breaks. So it looks correct on the directory website but fails for native/app consumers of the raw file.
Scope / reproduction
Reproduced across multiple slugs:
https://s.w.org/plugins/geopattern-icon/cd-bp-avatar-bubble_6c6c6c.svg→width="60" height="60" viewbox="0 0 60 60"https://s.w.org/plugins/geopattern-icon/bp-extend-widgets_6c6c6c.svg→width="465" height="465" viewbox="0 0 465 465"https://s.w.org/plugins/geopattern-icon/hello-dolly_6c6c6c.svg→width="276" height="276" viewbox="0 0 276 276"
The dimensions differ per plugin, but the lowercase viewbox is present in every one — confirming a single generator template. The files are well-formed XML (xmllint --noout passes); this is a semantic / spec-conformance bug, not a syntax error.
Secondary issues (not spec violations, but low-quality generator output)
preserveAspectRatio="none"is inert — per spec it only takes effect when a validviewBoxis present. Once the viewBox casing is fixed,="none"will begin _stretching/distorting_ the pattern whenever the icon is rendered non-square.xMidYMid meetis almost certainly the intended value for an icon.- Excessive floating-point precision on opacity (and transform/points) values, e.g.
fill-opacity="0.080666666666667","0.10666666666667"— up to \~14 decimal places. Opacity is quantized to 8 bits at render time, so this is visually identical to \~3 decimals (0.081) while bloating the file (this 6.8 KB icon could be under 2 KB). Rounding all numeric output to \~3 decimals would help. pointsuses commas as the only separator between every number (points="3.3,0,6.7,0,10,3.3,…") rather than comma-separated coordinate _pairs_ delimited by spaces ("3.3,0 6.7,0 10,3.3 …"). Technically valid per the SVG number grammar, but unconventional, hard to read, and historically a parser-compatibility hazard. The paired form is safer.
Change History (4)
This ticket was mentioned in PR #658 on WordPress/wordpress.org by @dd32.
7 weeks ago
#1
- Keywords has-patch added
This ticket was mentioned in PR #659 on WordPress/wordpress.org by @dd32.
7 weeks ago
#2
## Summary
Follow-up to #658, addressing the rest of meta.trac #8270.
Updates the bundled `RedeyeVentures/GeoPattern` library from 1.1.0 → 1.1.2 (the latest release), then applies two small local patches for the "secondary issues" the ticket raised about low-quality generator output.
## Library update (1.1.0 → 1.1.2)
Our vendored copy already carried two of 1.1.2's three changes as prior local patches (getString() and the <?xml?> prolog). The only outstanding upstream change was a one-character bug fix:
geoXes(): a missing closing)on arotate()transform produced a malformedtransform="… rotate(45, x, y"on the pattern's bottom-right tiling element.
The directory was renamed geopattern-1.1.0 → geopattern-1.1.2; the loader require and both PHPCS exclude-patterns were updated to match (the only references to the path).
## Local patches on top of 1.1.2
These are deliberate deviations from upstream (commented in-code, referencing the ticket, so they can be re-applied on a future bump):
- Round generated floats to 3 decimals at serialization (
Base.php). Upstream emitted full PHP precision, e.g.fill-opacity="0.080666666666667"— invisible once rendered but bloating every icon. Covers opacity, coordinates, transforms and path data. - Emit
pointsas space-delimitedx,ypairs (Polyline.php), e.g."3,0 6,0", instead of one flat comma-separated list of every number — the conventional, parser-safe encoding.
## Verification
Generated icons for all 17 pattern types via the library directly:
- Max decimal places in output dropped from ~14 to 3.
pointsnow paired:points="0,15.935 9.2,0 27.6,0 …".- File size reduced ~20-25% on pattern-heavy icons (akismet, jetpack, woocommerce, bbpress).
- All 17 generators produce well-formed XML with balanced transform parens (confirms the geoXes fix).
Rendering is unchanged to the eye — rounding is sub-unit on 60-465px patterns and the points change is separator-only.
Note: the lowercase
viewBoxcasing bug from the same ticket is fixed separately in #658 (it lives in ourPlugin_Geopattern_SVGoverride, not the library). This PR is independent and touches different files.
## Test plan
- [ ] Request a generated icon (
/geopattern-icon/<slug>.svg) and confirm opacity/coordinate values are at most 3 decimals andpointsare space-separated pairs. - [ ] Confirm the icon still passes
xmllint --nooutand renders identically. - [ ] Spot-check an "xes" pattern icon for a well-formed
rotate(...)transform.
🤖 Generated with Claude Code
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)
## Summary
Fixes meta.trac #8270.
The auto-generated fallback "geopattern" plugin icons served from
https://s.w.org/plugins/geopattern-icon/<slug>_<hex>.svgemitted theviewBoxattribute in all-lowercase (viewbox). SVG attribute names are case-sensitive, so spec-compliant parsers treat it as an unknown attribute and the document effectively has noviewBox. Without a user coordinate system the icon cannot be scaled and renders garbled in native/strict renderers — notably Apple's CoreSVG (ImageIO, native iOS/macOS image loading) when the file is fetched directly asimage/svg+xml.It went unnoticed because, when an SVG is inlined into HTML, the parser's foreign-content attribute-adjustment step auto-corrects
viewbox→viewBox, so it renders fine on the directory website. The standalone file fetched via<img>/ CSSbackground-image/ native loaders gets no such correction.The fix is a single casing change in the generator template (
class-plugin-geopattern-svg.php):The internal property name is left as
$viewbox(private implementation detail); only the emitted attribute changes.## Notes / scope decisions
preserveAspectRatio="none"was intentionally left as-is. The ticket suggestsxMidYMid meet, but.plugin-iconrenders these in a fixed square box, and browsers already applyviewBox(auto-corrected) +none, i.e. stretch-to-fill — the established appearance on the directory today. Fixing only the casing makes native/CoreSVG renderers match that current behaviour; switching tomeetwould change rendering (letterboxing for non-square patterns). Happy to flip it if a stretch-vs-letterbox change is wanted.pointsseparators) are non-spec-violation polish living in the vendoredlibs/geopattern-1.1.0/library, so they are left out of this minimal, low-risk fix and can be a follow-up if desired.## Test plan
/geopattern-icon/<slug>.svg) and confirm the root element now containsviewBox="0 0 W H".xmllint --nooutand renders identically in a browser.image/svg+xmlin a strict/native renderer (e.g. macOS Quick Look / an<img>tag).🤖 Generated with Claude Code