1/************************************************ 2 * LEAF IMAGE MASK â GUTENBERG SAFE (FIXED) 3 ************************************************/ 4(function () { 5 if (!document.body?.classList.contains("block-editor-page")) return; 6 7 let uid = 0; 8 9 function applyLeaf(block) { 10 const figure = block.querySelector("figure"); 11 const img = figure?.querySelector("img"); 12 if (!figure || !img) return; 13 14 // Always cleanup first 15 const oldSvg = figure.querySelector(".leaf-svg"); 16 if (oldSvg) oldSvg.remove(); 17 18 // Reset image visibility by default 19 img.style.opacity = ""; 20 21 let color = null; 22 if (block.classList.contains("custom_media")) color = "#d27d29"; 23 if (block.classList.contains("custom_media_optional")) color = "#0f8642"; 24 25 // ð NO LEAF: stop here, image stays normal 26 if (!color) { 27 return; 28 } 29 30 uid++; 31 const clipId = `leafClip-${uid}`; 32 const imgSrc = img.currentSrc || img.src; 33 34 const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); 35 svg.classList.add("leaf-svg"); 36 svg.setAttribute("viewBox", "0 0 548 459"); 37 svg.style.cssText = ` 38 position:absolute; 39 inset:0; 40 width:100%; 41 height:100%; 42 z-index:1; 43 pointer-events:none; 44 `; 45 46 svg.innerHTML = ` 47 <defs> 48 <clipPath id="${clipId}"> 49 <path d="M348.848 454.743C73.6394 467.664 -32.5061 327.996 8.97387 126.977C50.4539 -74.0415 96.3323 22.045 168.034 36.1563C350.424 77.7852 538.681 150.957 547.301 358.488C550.867 496.795 407.87 449.732 348.848 454.743Z"/> 50 </clipPath> 51 </defs> 52 53 <image 54 href="${imgSrc}" 55 width="548" 56 height="459" 57 preserveAspectRatio="xMidYMid slice" 58 clip-path="url(#${clipId})" 59 /> 60 61 <path 62 d="M348.848 454.743C73.6394 467.664 -32.5061 327.996 8.97387 126.977C50.4539 -74.0415 96.3323 22.045 168.034 36.1563C350.424 77.7852 538.681 150.957 547.301 358.488C550.867 496.795 407.87 449.732 348.848 454.743Z" 63 fill="none" 64 stroke="${color}" 65 stroke-width="18" 66 /> 67 `; 68 69 figure.style.position = "relative"; 70 71 // Hide original img ONLY when leaf active 72 img.style.opacity = "0"; 73 74 figure.appendChild(svg); 75 } 76 77 function refresh() { 78 document.querySelectorAll(".wp-block-media-text").forEach(applyLeaf); 79 } 80 81 const observer = new MutationObserver(() => { 82 requestAnimationFrame(refresh); 83 }); 84 85 observer.observe(document.body, { childList: true, subtree: true }); 86 setTimeout(refresh, 800); 87})(); 88 89/************************************************ 90 * INSPECTOR CONTROLS (UNCHANGED) 91 ************************************************/ 92(function (wp) { 93 if (!wp) return; 94 95 const { createElement: el, Fragment } = wp.element; 96 const { InspectorControls } = wp.blockEditor || wp.editor; 97 const { PanelBody, CheckboxControl } = wp.components; 98 const { createHigherOrderComponent } = wp.compose; 99 const { addFilter } = wp.hooks; 100 101 const TARGET = "core/media-text"; 102 103 const withLeaf = createHigherOrderComponent((BlockEdit) => { 104 return (props) => { 105 if (props.name !== TARGET) return el(BlockEdit, props); 106 107 const cls = props.attributes.className || ""; 108 109 return el( 110 Fragment, 111 {}, 112 el(BlockEdit, props), 113 el( 114 InspectorControls, 115 {}, 116 el( 117 PanelBody, 118 { title: "Leaf Options", initialOpen: true }, 119 el(CheckboxControl, { 120 label: "Orange Leaf", 121 checked: cls === "custom_media", 122 onChange: (v) => 123 props.setAttributes({ className: v ? "custom_media" : "" }) 124 }), 125 el(CheckboxControl, { 126 label: "Green Leaf", 127 checked: cls === "custom_media_optional", 128 onChange: (v) => 129 props.setAttributes({ 130 className: v ? "custom_media_optional" : "" 131 }) 132 }), 133 el(CheckboxControl, { 134 label: "No Leaf", 135 checked: cls === "", 136 onChange: () => 137 props.setAttributes({ className: "" }) 138 }) 139 ) 140 ) 141 ); 142 }; 143 }, "withLeaf"); 144 145 addFilter( 146 "editor.BlockEdit", 147 "leaf/media-text-final-fix", 148 withLeaf 149 ); 150})(window.wp); 151 152/************************************************ 153 * ACF DUPLICATE BLOCK ID SAFEGUARD 154 * Cloning a Kadence accordion (or any block) copies the ACF 155 * block "id" attribute, so two blocks share field data and 156 * content disappears on save. Regenerate the id as soon as a 157 * duplicate appears anywhere in the block tree. 158 ************************************************/ 159(function (wp) { 160 if (!wp || !wp.data) return; 161 162 const { select, dispatch, subscribe } = wp.data; 163 164 function freshAcfBlockId() { 165 return ( 166 "block_" + 167 Date.now().toString(36) + 168 Math.random().toString(36).slice(2, 10) 169 ); 170 } 171 172 function collectAcfBlocks(blocks, out) { 173 for (const block of blocks) { 174 if (block.name && block.name.indexOf("acf/") === 0) out.push(block); 175 if (block.innerBlocks && block.innerBlocks.length) { 176 collectAcfBlocks(block.innerBlocks, out); 177 } 178 } 179 return out; 180 } 181 182 let lastTree = null; 183 let fixing = false; 184 185 subscribe(() => { 186 if (fixing) return; 187 188 const editor = select("core/block-editor"); 189 if (!editor) return; 190 191 // getBlocks() is memoized: same reference means nothing changed. 192 const tree = editor.getBlocks(); 193 if (tree === lastTree) return; 194 lastTree = tree; 195 196 const seen = {}; 197 const duplicates = []; 198 199 for (const block of collectAcfBlocks(tree, [])) { 200 const id = block.attributes && block.attributes.id; 201 if (!id) continue; 202 if (seen[id]) duplicates.push(block.clientId); 203 else seen[id] = true; 204 } 205
206 if (!duplicates.length) return; 207 208 fixing = true; 209 const be = dispatch("core/block-editor"); 210 for (const clientId of duplicates) { 211 if (be.__unstableMarkNextChangeAsNotPersistent) { 212 be.__unstableMarkNextChangeAsNotPersistent(); 213 } 214 be.updateBlockAttributes(clientId, { id: freshAcfBlockId() }); 215 } 216 fixing = false; 217 }); 218})(window.wp);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.