{"id":177573,"date":"2026-08-06T12:09:08","date_gmt":"2026-08-06T10:09:08","guid":{"rendered":"https:\/\/de.wordpress.org\/support\/topic\/custom-stroke-svg-icons-render-solid-filled-on-frontend-but-correct-in-editor\/"},"modified":"2026-08-06T16:13:25","modified_gmt":"2026-08-06T14:13:25","slug":"custom-stroke-svg-icons-render-solid-filled-on-frontend-but-correct-in-editor","status":"closed","type":"topic","link":"https:\/\/de.wordpress.org\/support\/topic\/custom-stroke-svg-icons-render-solid-filled-on-frontend-but-correct-in-editor\/","title":{"rendered":"Custom stroke SVG icons render solid-filled on frontend, but correct in editor"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><strong>Plugin &amp; Version:<\/strong> Kadence Blocks (Free), v3.7.9 \u2014 issue originates in <code>includes\/class-kadence-blocks-svg.php<\/code><br \/><strong>Also affects:<\/strong> Kadence Blocks Pro custom icons (upload feature), since the frontend render path is shared<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Summary:<\/strong><br \/>Custom SVG icons uploaded via the Kadence Blocks Pro icon manager, built with <code>fill=\"none\"<\/code> and <code>stroke=\"currentColor\"<\/code> on each element (the standard &#8222;line icon&#8220; pattern, e.g. Feather-style icons), render correctly in the block editor but appear as solid filled shapes on the published frontend.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Root cause:<\/strong><br \/>The block editor (JS) and the frontend (PHP) use two separate code paths to reconstruct the stored SVG from the icon&#8217;s <code>{vB, cD: [{nE, aBs}]}<\/code> JSON structure, and only the JS path correctly restores stroke-icon styling.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In <code>class-kadence-blocks-svg.php<\/code>, method <code>generate_svg_elements()<\/code>:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">php<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>foreach ( $aBs as $key =&gt; $attribute ) {\n    if ( ! in_array( $key, array( 'fill', 'stroke', 'none' ) ) ) {\n        $tmpAttr&#091; $key ] = $key . '=\"' . esc_attr( $attribute ) . '\"';\n    }\n}\n\nif ( isset( $aBs&#091;'fill'], $aBs&#091;'stroke'] ) &amp;&amp; $aBs&#091;'fill'] === 'none' ) {\n    $tmpAttr&#091;'stroke'] = 'stroke=\"currentColor\"';\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><code>fill<\/code> and <code>stroke<\/code> are always stripped from each element by name in the first loop. The second block only re-adds <code>stroke=\"currentColor\"<\/code> when the element originally had both <code>fill=\"none\"<\/code> and a <code>stroke<\/code> attribute \u2014 but it never re-adds <code>fill=\"none\"<\/code>. The element ends up with a <code>stroke<\/code> but no <code>fill<\/code>, so it inherits <code>fill=\"currentColor\"<\/code> from the parent <code>&lt;svg&gt;<\/code> wrapper (which is set unconditionally for custom icons) \u2014 resulting in a solid filled shape instead of an outlined one.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For comparison, the equivalent editor-side JS logic (in the compiled <code>blocks-icon.js<\/code>) handles this correctly by restoring <strong>both<\/strong> attributes:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">js<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>if (attrs.fill === 'none' &amp;&amp; attrs.stroke) {\n  override = { fill: 'none', stroke: 'currentColor' };\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Steps to reproduce:<\/strong><\/p>\n\n\n\n<ol>\n<li>Create an SVG icon where every element has both <code>fill=\"none\"<\/code> and <code>stroke=\"currentColor\"<\/code> (plus <code>stroke-width<\/code>, <code>stroke-linecap<\/code>, <code>stroke-linejoin<\/code> as needed), e.g. a simple rounded rectangle.<\/li>\n\n\n\n<li>Upload it via Kadence Blocks Pro \u2192 Icon Manager (&#8222;My Icons&#8220;).<\/li>\n\n\n\n<li>Insert the icon into any icon-capable block (Icon, Info Box, Icon List, etc.).<\/li>\n\n\n\n<li>Compare the block editor preview (correct, outlined) with the published page (incorrect, solid fill).<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Expected behavior:<\/strong> Frontend rendering matches the editor rendering.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Suggested fix:<\/strong> In <code>generate_svg_elements()<\/code>, restore <code>fill=\"none\"<\/code> alongside <code>stroke=\"currentColor\"<\/code> when the condition is met, mirroring the JS implementation:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">php<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>if ( isset( $aBs&#091;'fill'], $aBs&#091;'stroke'] ) &amp;&amp; $aBs&#091;'fill'] === 'none' ) {\n    $tmpAttr&#091;'fill'] = 'fill=\"none\"';\n    $tmpAttr&#091;'stroke'] = 'stroke=\"currentColor\"';\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Current workaround<\/strong> (until fixed): targeted CSS forcing <code>fill: none<\/code> on elements that carry a <code>stroke<\/code> attribute:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">css<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>.kb-svg-icon-wrap svg &#091;stroke] { fill: none; }<\/code><\/pre>\n","protected":false},"template":"","class_list":["post-177573","topic","type-topic","status-closed","hentry"],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/de.wordpress.org\/support\/wp-json\/wp\/v2\/topic\/177573","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/de.wordpress.org\/support\/wp-json\/wp\/v2\/topic"}],"about":[{"href":"https:\/\/de.wordpress.org\/support\/wp-json\/wp\/v2\/types\/topic"}],"version-history":[{"count":0,"href":"https:\/\/de.wordpress.org\/support\/wp-json\/wp\/v2\/topic\/177573\/revisions"}],"wp:attachment":[{"href":"https:\/\/de.wordpress.org\/support\/wp-json\/wp\/v2\/media?parent=177573"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}