Plugin Directory

Changeset 3415636


Ignore:
Timestamp:
12/09/2025 04:55:01 PM (4 months ago)
Author:
courane01
Message:

Deploy version 1.0.1 to trunk

  • Fix plugin naming: now consistently uses 'Link Extension for XFN'
  • Fix installation directory path (xfn-link-extension → link-extension-for-xfn)
  • Fix Settings menu name (XFN Link Extension → Link Extension for XFN)
  • Change Contributors to Developers in plugin header
  • Update all documentation and user-facing strings
Location:
link-extension-for-xfn
Files:
8 added
5 edited

Legend:

Unmodified
Added
Removed
  • link-extension-for-xfn/trunk/build/index.asset.php

    r3415429 r3415636  
    1 <?php return array('dependencies' => array('react-jsx-runtime', 'wp-block-editor', 'wp-components', 'wp-compose', 'wp-data', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-rich-text'), 'version' => 'a7ec83b0894a6256c5f3');
     1<?php return array('dependencies' => array('react-jsx-runtime', 'wp-block-editor', 'wp-components', 'wp-compose', 'wp-data', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-rich-text'), 'version' => '36fd7e2b8a644596151d');
  • link-extension-for-xfn/trunk/build/index.js

    r3415429 r3415636  
    1 (()=>{"use strict";const e=window.wp.i18n,n=window.wp.hooks,o=window.wp.components,t=window.wp.blockEditor,l=window.wp.compose,i=(window.wp.element,window.wp.data,window.wp.richText),s=window.ReactJSXRuntime;(0,i.registerFormatType)("xfn-link-extension/xfn-rel",{title:(0,e.__)("XFN Relationship","link-extension-for-xfn"),tagName:"a",className:null,attributes:{rel:"rel",href:"href"},edit:()=>null}),console.log("[XFN] XFN format type registered");const r={friendship:{type:"radio",label:(0,e.__)("Friendship","link-extension-for-xfn"),description:(0,e.__)("Your friendship level (choose one)","link-extension-for-xfn"),options:[{label:(0,e.__)("Contact","link-extension-for-xfn"),value:"contact"},{label:(0,e.__)("Acquaintance","link-extension-for-xfn"),value:"acquaintance"},{label:(0,e.__)("Friend","link-extension-for-xfn"),value:"friend"}]},physical:{type:"checkbox",label:(0,e.__)("Physical","link-extension-for-xfn"),description:(0,e.__)("Have you met this person?","link-extension-for-xfn"),options:[{label:(0,e.__)("Met","link-extension-for-xfn"),value:"met"}]},professional:{type:"checkbox",label:(0,e.__)("Professional","link-extension-for-xfn"),description:(0,e.__)("Professional relationships","link-extension-for-xfn"),options:[{label:(0,e.__)("Co-worker","link-extension-for-xfn"),value:"co-worker"},{label:(0,e.__)("Colleague","link-extension-for-xfn"),value:"colleague"}]},geographical:{type:"radio",label:(0,e.__)("Geographical","link-extension-for-xfn"),description:(0,e.__)("Geographical relationship","link-extension-for-xfn"),options:[{label:(0,e.__)("Co-resident","link-extension-for-xfn"),value:"co-resident"},{label:(0,e.__)("Neighbor","link-extension-for-xfn"),value:"neighbor"}]},family:{type:"radio",label:(0,e.__)("Family","link-extension-for-xfn"),description:(0,e.__)("Family relationship","link-extension-for-xfn"),options:[{label:(0,e.__)("Child","link-extension-for-xfn"),value:"child"},{label:(0,e.__)("Parent","link-extension-for-xfn"),value:"parent"},{label:(0,e.__)("Sibling","link-extension-for-xfn"),value:"sibling"},{label:(0,e.__)("Spouse","link-extension-for-xfn"),value:"spouse"},{label:(0,e.__)("Kin","link-extension-for-xfn"),value:"kin"}]},romantic:{type:"checkbox",label:(0,e.__)("Romantic","link-extension-for-xfn"),description:(0,e.__)("Romantic relationships","link-extension-for-xfn"),options:[{label:(0,e.__)("Muse","link-extension-for-xfn"),value:"muse"},{label:(0,e.__)("Crush","link-extension-for-xfn"),value:"crush"},{label:(0,e.__)("Date","link-extension-for-xfn"),value:"date"},{label:(0,e.__)("Sweetheart","link-extension-for-xfn"),value:"sweetheart"}]},identity:{type:"checkbox",label:(0,e.__)("Identity","link-extension-for-xfn"),description:(0,e.__)("Is this your own content?","link-extension-for-xfn"),options:[{label:(0,e.__)("Me","link-extension-for-xfn"),value:"me"}]}};function c(e){if(!e)return{xfn:[],other:[]};const n=["contact","acquaintance","friend","met","co-worker","colleague","co-resident","neighbor","child","parent","sibling","spouse","kin","muse","crush","date","sweetheart","me"],o=e.split(/\s+/).filter(Boolean),t=[],l=[];return o.forEach(e=>{n.includes(e)?t.push(e):l.push(e)}),{xfn:t,other:l}}function a(e,n){const o=[...n,...e].filter(Boolean);return[...new Set(o)].join(" ")}function d(e,n){return e.rel?e.rel:e.metadata?.rel?e.metadata.rel:""}const u=({attributes:n,setAttributes:l,name:i})=>{const u=d(n),{xfn:p,other:g}=c(u),f=(e,o,t)=>{let i=[...p];if("radio"===r[e].type){const n=r[e].options.map(e=>e.value);i=i.filter(e=>!n.includes(e)),t&&i.push(o)}else t?i.includes(o)||i.push(o):i=i.filter(e=>e!==o);(e=>{const o=a(e,g);!function(e,n,o){e.hasOwnProperty("rel")?n({rel:o||void 0}):n({metadata:{...e.metadata||{},rel:o||void 0}})}(n,l,o)})(i)},b=["core/button","core/image","core/navigation-link","core/site-logo","core/post-title","core/query-title"].includes(i);return(0,s.jsx)(t.InspectorControls,{children:(0,s.jsxs)(o.PanelBody,{title:(0,e.__)("XFN Relationships","link-extension-for-xfn"),initialOpen:b,className:"xfn-inspector-panel",children:[(0,s.jsx)("p",{className:"xfn-panel-description",children:(0,e.__)("Describe your relationship to the people or organizations you link to using XFN (XHTML Friends Network) markup.","link-extension-for-xfn")}),Object.entries(r).map(([n,t])=>{if("radio"===t.type){const l=t.options.find(e=>p.includes(e.value))?.value||"",i=[{label:(0,e.__)("None","link-extension-for-xfn"),value:""},...t.options];return(0,s.jsx)("div",{className:"xfn-category-section",children:(0,s.jsx)(o.RadioControl,{label:t.label,help:t.description,selected:l,options:i,onChange:e=>{f(n,e,""!==e)}})},n)}return(0,s.jsxs)("div",{className:"xfn-category-section",children:[(0,s.jsx)("h4",{className:"xfn-category-title",children:t.label}),(0,s.jsx)("p",{className:"xfn-category-help",children:t.description}),t.options.map(e=>(0,s.jsx)(o.CheckboxControl,{label:e.label,checked:p.includes(e.value),onChange:o=>{f(n,e.value,o)}},e.value))]},n)}),p.length>0&&(0,s.jsxs)("div",{className:"xfn-selected-summary",children:[(0,s.jsx)("h4",{children:(0,e.__)("Selected Relationships:","link-extension-for-xfn")}),(0,s.jsx)("div",{className:"xfn-pills",children:p.map(e=>(0,s.jsx)("span",{className:`xfn-pill xfn-pill-${e}`,children:e},e))})]})]})})};let p=[],g=[],f=null,b=null;function x(){setTimeout(()=>{const n=document.querySelector(".block-editor-link-control");if(!n)return;const o=n.querySelector(".block-editor-link-control__tools .components-button");if(!o)return;if("true"!==o.getAttribute("aria-expanded"))return;const t=n.querySelector(".block-editor-link-control__settings");if(!t)return;if(t.querySelector(".xfn-collapsible-section"))return;console.log("[XFN] Attempting to find link value from React...");const l=n,i=Object.keys(l).find(e=>e.startsWith("__react"));if(i){const e=l[i];console.log("[XFN] React instance found:",e);let n=e,o=0;for(;n&&o<10;){if(n.memoizedProps?.value){b=n.memoizedProps.value,f=n.memoizedProps.onChange,window.currentLinkValue=b,window.currentLinkOnChange=f,console.log("[XFN] Found link value:",b),console.log("[XFN] Link value keys:",Object.keys(b)),console.log("[XFN] Link value rel:",b.rel),console.log("[XFN] Found onChange:",f);break}n=n.return||n._owner,o++}}console.log("[XFN] Looking for rel input in link control...");const s=t.querySelectorAll("input");console.log("[XFN] All inputs in settings panel:",s),s.forEach((e,n)=>{console.log(`[XFN] Input ${n}:`,{type:e.type,id:e.id,name:e.name,placeholder:e.placeholder,value:e.value,element:e})});let u=n.querySelector('input[type="text"][placeholder*="rel" i]');if(console.log("[XFN] Try 1 (placeholder*=rel):",u),u||(u=n.querySelector('input[id*="rel" i]'),console.log("[XFN] Try 2 (id*=rel):",u)),!u){const e=t.querySelectorAll('input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"])');console.log("[XFN] Try 3 - text-like inputs in settings:",e),e.length>0&&(u=e[e.length-1])}console.log("[XFN] Final rel input found:",!!u),u&&(console.log("[XFN] Rel input element:",u),console.log("[XFN] Rel input current value:",u.value));let x="";const h=wp.data.select("core/block-editor").getSelectedBlock();if(h&&["core/button","core/image","core/navigation-link","core/site-logo","core/post-title","core/query-title"].includes(h.name))x=d(h.attributes,h.name),console.log("[XFN] Got rel from block-level link attributes:",x);else if(b?.url&&h?.attributes?.content){let e=h.attributes.content;if("object"==typeof e&&e.toHTMLString&&(e=e.toHTMLString()),"string"==typeof e&&e.includes(b.url)){const n=(new DOMParser).parseFromString(e,"text/html"),o=Array.from(n.querySelectorAll("a")).find(e=>e.getAttribute("href")===b.url);o&&(x=o.getAttribute("rel")||"",console.log("[XFN] Got rel from existing link in content:",x))}}!x&&b&&b.rel?(x=b.rel,console.log("[XFN] Got rel from link value:",x)):!x&&u&&(x=u.value,console.log("[XFN] Got rel from input:",x));const{xfn:N,other:F}=c(x);p=[...N],g=[...F],console.log("[XFN] Initial XFN values:",p),console.log("[XFN] Initial other values:",g);const m=document.createElement("div");m.className="xfn-collapsible-section",m.innerHTML=function(n){let o=`\n\t\t<button \n\t\t\tclass="xfn-section-toggle components-button is-tertiary" \n\t\t\taria-expanded="false" \n\t\t\ttype="button"\n\t\t>\n\t\t\tXFN ${n.length>0?`<span class="xfn-count-badge">${n.length}</span>`:""}\n\t\t\t<svg class="xfn-chevron" width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">\n\t\t\t\t<path d="M17.5 11.6L12 16l-5.5-4.4.9-1.2L12 14l4.5-3.6 1 1.2z"/>\n\t\t\t</svg>\n\t\t</button>\n\t\t<div class="xfn-section-content" style="display: none;">\n\t\t\t<p class="xfn-section-description">\n\t\t\t\t${(0,e.__)("Describe your relationship to this person or organization","link-extension-for-xfn")}\n\t\t\t</p>\n\t`;return Object.entries(r).forEach(([t,l])=>{if(o+=`<div class="xfn-category" data-category="${t}">`,o+=`<h4>${l.label}</h4>`,"radio"===l.type){const t=l.options.find(e=>n.includes(e.value))?.value||"";o+='<div class="xfn-button-group">',o+=`<button class="components-button is-compact ${""===t?"is-pressed":""}" data-value="">${(0,e.__)("None","link-extension-for-xfn")}</button>`,l.options.forEach(e=>{o+=`<button class="components-button is-compact ${t===e.value?"is-pressed":""}" data-value="${e.value}">${e.label}</button>`}),o+="</div>"}else o+='<div class="xfn-button-group">',l.options.forEach(e=>{const t=n.includes(e.value);o+=`<button class="components-button is-compact ${t?"is-pressed":""}" data-value="${e.value}">${e.label}</button>`}),o+="</div>";o+="</div>"}),n.length>0&&(o+='<div class="xfn-summary">',o+=`<h4>${(0,e.__)("Active Relationships:","link-extension-for-xfn")}</h4>`,o+='<div class="xfn-pills">',n.forEach(e=>{o+=`<span class="xfn-pill xfn-pill-${e}">${e}</span> `}),o+="</div></div>"),o+="</div>",o}(p),t.appendChild(m),function(n,o){const t=n.querySelector(".xfn-section-toggle"),l=n.querySelector(".xfn-section-content"),i=t.querySelector(".xfn-chevron"),s=n.closest(".block-editor-link-control")||document;t.addEventListener("click",e=>{e.preventDefault(),e.stopPropagation();const n=!("true"===t.getAttribute("aria-expanded"));t.setAttribute("aria-expanded",n),l.style.display=n?"block":"none",i.style.transform=n?"rotate(180deg)":"rotate(0deg)"}),n.querySelectorAll(".xfn-button-group .components-button").forEach(l=>{l.addEventListener("click",l=>{l.preventDefault(),l.stopPropagation();const i=l.target.closest(".xfn-category").dataset.category,c=l.target.dataset.value,d=l.target.closest(".xfn-button-group");if("radio"===r[i].type){const e=r[i].options.map(e=>e.value);p=p.filter(n=>!e.includes(n)),c&&p.push(c),d.querySelectorAll(".components-button").forEach(e=>{e.classList.remove("is-pressed")}),l.target.classList.add("is-pressed")}else l.target.classList.contains("is-pressed")?(p=p.filter(e=>e!==c),l.target.classList.remove("is-pressed")):(p.includes(c)||p.push(c),l.target.classList.add("is-pressed"));(()=>{const l=a(p,g);if(console.log("[XFN] Updating XFN values:",{xfnValues:p,otherValues:g,newRel:l}),o){o.value=l,console.log("[XFN] Updated rel input field to:",l);const e=new Event("input",{bubbles:!0});o.dispatchEvent(e);const n=new Event("change",{bubbles:!0});o.dispatchEvent(n)}window.pendingXFNRel=l,window.pendingXFNUrl=b?.url,console.log("[XFN] Stored pending XFN rel:",window.pendingXFNRel),console.log("[XFN] Stored pending XFN url:",window.pendingXFNUrl),b={...b||{},rel:l||""},console.log("[XFN] Stored rel value (will apply on Submit):",b);const i=s.querySelector('.block-editor-link-control__search-submit, button[type="submit"]');i&&(i.removeAttribute("aria-disabled"),i.removeAttribute("disabled"),i.classList.add("xfn-apply-ready")),function(n){let o=n.querySelector(".xfn-summary");if(0===p.length)return void(o&&o.remove());o||(o=document.createElement("div"),o.className="xfn-summary",n.querySelector(".xfn-section-content").appendChild(o));let t=`<h4>${(0,e.__)("Active Relationships:","link-extension-for-xfn")}</h4>`;t+='<div class="xfn-pills">',p.forEach(e=>{t+=`<span class="xfn-pill xfn-pill-${e}">${e}</span> `}),t+="</div>",o.innerHTML=t}(n),function(e){let n=e.querySelector(".xfn-count-badge");0!==p.length?(n||(n=document.createElement("span"),n.className="xfn-count-badge",e.insertBefore(n,e.querySelector(".xfn-chevron"))),n.textContent=p.length):n&&n.remove()}(t)})()})})}(m,u),console.log("[XFN] Looking for Apply button...");const X=n.querySelectorAll("button");console.log("[XFN] All buttons in link control:",X);const w=n.querySelector('.block-editor-link-control__search-submit, button[type="submit"]');w?(console.log("[XFN] Found Apply button (will save XFN on click)"),w.addEventListener("click",e=>{if(console.log("[XFN] ===== Apply button clicked! ====="),console.log("[XFN] Current XFN values:",p),console.log("[XFN] Current link value:",b),p.length>0){const e=a(p,g);console.log("[XFN] Storing XFN rel for post-link-creation:",e),window.pendingXFNRel=e,window.pendingXFNUrl=b?.url,console.log("[XFN] Scheduling XFN application attempts..."),setTimeout(()=>{console.log("[XFN] Attempt 1 (100ms)..."),k()},100),setTimeout(()=>{console.log("[XFN] Attempt 2 (300ms)..."),k()},300),setTimeout(()=>{console.log("[XFN] Attempt 3 (500ms)..."),k()},500),setTimeout(()=>{console.log("[XFN] Attempt 4 (1000ms)..."),k()},1e3)}else console.log("[XFN] No XFN values selected, skipping");o&&"true"===o.getAttribute("aria-expanded")&&setTimeout(()=>o.click(),150)},!0),console.log("[XFN] Apply button interceptor attached")):console.warn("[XFN] Apply button not found!")},100)}function k(){if(console.log("[XFN] ===== Applying XFN to created link ====="),console.log("[XFN] Pending XFN rel:",window.pendingXFNRel),console.log("[XFN] Pending XFN url:",window.pendingXFNUrl),!window.pendingXFNRel||!window.pendingXFNUrl)return console.log("[XFN] No pending XFN data to apply"),!1;const e=wp.data.select("core/block-editor").getSelectedBlock();if(!e)return console.log("[XFN] No selected block found"),!1;if(console.log("[XFN] Selected block:",e.name),console.log("[XFN] Selected block clientId:",e.clientId),console.log("[XFN] Selected block attributes:",e.attributes),console.log("[XFN] Block innerBlocks:",e.innerBlocks),["core/button","core/image","core/navigation-link","core/site-logo","core/post-title","core/query-title"].includes(e.name)){console.log("[XFN] This is a block-level link, updating rel attribute directly...");const n=d(e.attributes,e.name);console.log("[XFN] Existing rel:",n);const{other:o}=c(n);console.log("[XFN] Existing other values:",o);const{xfn:t}=c(window.pendingXFNRel);console.log("[XFN] Pending XFN values:",t);const l=a(t,o);if(console.log("[XFN] New combined rel:",l),e.attributes.hasOwnProperty("rel"))wp.data.dispatch("core/block-editor").updateBlockAttributes(e.clientId,{rel:l||void 0}),console.log("[XFN] ✓ Updated rel attribute on block");else{const n=e.attributes.metadata||{};wp.data.dispatch("core/block-editor").updateBlockAttributes(e.clientId,{metadata:{...n,rel:l||void 0}}),console.log("[XFN] ✓ Updated metadata.rel attribute on block")}if(window.currentLinkOnChange&&"function"==typeof window.currentLinkOnChange)try{const e={...window.currentLinkValue||{},rel:l||""};window.currentLinkOnChange(e),console.log("[XFN] ✓ Also called onChange with updated rel")}catch(e){console.warn("[XFN] Could not call onChange:",e)}return window.pendingXFNRel=null,window.pendingXFNUrl=null,console.log("[XFN] ✓✓✓ Block-level link updated successfully! ✓✓✓"),!0}let n=e.attributes.content;if(console.log("[XFN] Block content:",n),console.log("[XFN] Block content type:",typeof n),n&&"object"==typeof n&&n.toHTMLString&&(console.log("[XFN] Converting RichTextData to HTML string..."),n=n.toHTMLString(),console.log("[XFN] Converted content:",n)),!n||"string"!=typeof n)return console.warn("[XFN] Block has no string content or unable to convert to string"),!1;const o=n.includes(window.pendingXFNUrl);if(console.log("[XFN] URL in content?",o),!o)return console.warn("[XFN] Pending URL not found in block content"),console.log("[XFN] Looking for:",window.pendingXFNUrl),console.log("[XFN] In content:",n),!1;console.log("[XFN] Found URL in block content, attempting to update using proper WordPress approach...");try{const{xfn:o,other:t}=c(window.pendingXFNRel),l=(new DOMParser).parseFromString(n,"text/html"),i=l.querySelectorAll("a");let s=!1;if(i.forEach(e=>{if(e.getAttribute("href")===window.pendingXFNUrl){const n=e.getAttribute("rel")||"",{other:l}=c(n),i=a(o,l.length?l:t);console.log("[XFN] Setting rel attribute:",i),e.setAttribute("rel",i),s=!0}}),s){const n=l.body.innerHTML;return console.log("[XFN] Updating block with new content..."),wp.data.dispatch("core/block-editor").updateBlockAttributes(e.clientId,{content:n}),console.log("[XFN] ✓ Block content updated"),window.pendingXFNRel=null,window.pendingXFNUrl=null,setTimeout(()=>{const n=wp.data.select("core/block-editor").getBlock(e.clientId);console.log("[XFN] Verification - Current content:",n?.attributes?.content)},100),!0}}catch(e){console.error("[XFN] Error updating link:",e)}return console.warn("[XFN] Could not update link"),!1}const h=(0,l.createHigherOrderComponent)(e=>n=>{const{attributes:o,name:t}=n,l=window.linkexfoData?.settings||{enable_inspector_controls:!1,enable_floating_toolbar:!1};return(["core/button","core/image","core/navigation-link","core/site-logo","core/post-title","core/query-title"].includes(t)||o.hasOwnProperty("url")||o.hasOwnProperty("href")||o.hasOwnProperty("linkDestination"))&&l.enable_inspector_controls?(d(o),(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(e,{...n}),(0,s.jsx)(u,{...n})]})):(0,s.jsx)(e,{...n})},"withXFNControls");window.linkexfoData?.settings?.enable_inspector_controls&&((0,n.addFilter)("editor.BlockEdit","xfn-link-extension/with-xfn-controls",h),console.log("[XFN] Inspector Controls enabled")),(0,n.addFilter)("blocks.getSaveContent.extraProps","xfn-link-extension/add-rel-to-links",(e,n,o)=>(console.log("[XFN] getSaveContent filter called for:",n.name),p.length>0&&console.log("[XFN] Injecting XFN values into saved content:",p),e)),"undefined"!=typeof document&&(console.log("[XFN] Starting XFN monitoring in 1 second..."),setTimeout(()=>{console.log("[XFN] XFN monitoring started!"),new MutationObserver(e=>{e.forEach(e=>{"childList"===e.type&&Array.from(e.addedNodes).forEach(e=>{e.nodeType===Node.ELEMENT_NODE&&((e.classList?.contains("block-editor-link-control")||e.querySelector?.(".block-editor-link-control"))&&x(),(e.classList?.contains("block-editor-link-control__settings")||e.querySelector?.(".block-editor-link-control__settings"))&&x())}),"attributes"===e.type&&"aria-expanded"===e.attributeName&&x()})}).observe(document.body,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["aria-expanded"]}),document.addEventListener("click",e=>{e.target.closest(".block-editor-link-control__tools .components-button")&&setTimeout(x,50)})},1e3)),console.log("%c[XFN] Link Extension loaded successfully!","color: #00a32a; font-weight: bold; font-size: 14px;"),console.log("[XFN] Controls will appear in:");const N=window.linkexfoData?.settings||{enable_inspector_controls:!1,enable_floating_toolbar:!1};N.enable_inspector_controls?console.log("[XFN] ✓ Inspector Controls for link blocks (ENABLED)"):console.log("[XFN] ✗ Inspector Controls for link blocks (DISABLED - enable in Settings > Link Extension for XFN)"),N.enable_floating_toolbar?console.log("[XFN] ✓ Floating toolbar for link blocks (ENABLED)"):console.log("[XFN] ✗ Floating toolbar for link blocks (DISABLED - enable in Settings > Link Extension for XFN)"),console.log("[XFN] ✓ Collapsible XFN section in Link Advanced Panel (ALWAYS ENABLED)")})();
     1(()=>{"use strict";const e=window.wp.i18n,n=window.wp.hooks,o=window.wp.components,t=window.wp.blockEditor,l=window.wp.compose,i=(window.wp.element,window.wp.data,window.wp.richText),s=window.ReactJSXRuntime;(0,i.registerFormatType)("xfn-link-extension/xfn-rel",{title:(0,e.__)("XFN Relationship","link-extension-for-xfn"),tagName:"a",className:null,attributes:{rel:"rel",href:"href"},edit:()=>null}),console.log("[XFN] XFN format type registered");const r={friendship:{type:"radio",label:(0,e.__)("Friendship","link-extension-for-xfn"),description:(0,e.__)("Your friendship level (choose one)","link-extension-for-xfn"),options:[{label:(0,e.__)("Contact","link-extension-for-xfn"),value:"contact"},{label:(0,e.__)("Acquaintance","link-extension-for-xfn"),value:"acquaintance"},{label:(0,e.__)("Friend","link-extension-for-xfn"),value:"friend"}]},physical:{type:"checkbox",label:(0,e.__)("Physical","link-extension-for-xfn"),description:(0,e.__)("Have you met this person?","link-extension-for-xfn"),options:[{label:(0,e.__)("Met","link-extension-for-xfn"),value:"met"}]},professional:{type:"checkbox",label:(0,e.__)("Professional","link-extension-for-xfn"),description:(0,e.__)("Professional relationships","link-extension-for-xfn"),options:[{label:(0,e.__)("Co-worker","link-extension-for-xfn"),value:"co-worker"},{label:(0,e.__)("Colleague","link-extension-for-xfn"),value:"colleague"}]},geographical:{type:"radio",label:(0,e.__)("Geographical","link-extension-for-xfn"),description:(0,e.__)("Geographical relationship","link-extension-for-xfn"),options:[{label:(0,e.__)("Co-resident","link-extension-for-xfn"),value:"co-resident"},{label:(0,e.__)("Neighbor","link-extension-for-xfn"),value:"neighbor"}]},family:{type:"radio",label:(0,e.__)("Family","link-extension-for-xfn"),description:(0,e.__)("Family relationship","link-extension-for-xfn"),options:[{label:(0,e.__)("Child","link-extension-for-xfn"),value:"child"},{label:(0,e.__)("Parent","link-extension-for-xfn"),value:"parent"},{label:(0,e.__)("Sibling","link-extension-for-xfn"),value:"sibling"},{label:(0,e.__)("Spouse","link-extension-for-xfn"),value:"spouse"},{label:(0,e.__)("Kin","link-extension-for-xfn"),value:"kin"}]},romantic:{type:"checkbox",label:(0,e.__)("Romantic","link-extension-for-xfn"),description:(0,e.__)("Romantic relationships","link-extension-for-xfn"),options:[{label:(0,e.__)("Muse","link-extension-for-xfn"),value:"muse"},{label:(0,e.__)("Crush","link-extension-for-xfn"),value:"crush"},{label:(0,e.__)("Date","link-extension-for-xfn"),value:"date"},{label:(0,e.__)("Sweetheart","link-extension-for-xfn"),value:"sweetheart"}]},identity:{type:"checkbox",label:(0,e.__)("Identity","link-extension-for-xfn"),description:(0,e.__)("Is this your own content?","link-extension-for-xfn"),options:[{label:(0,e.__)("Me","link-extension-for-xfn"),value:"me"}]}};function c(e){if(!e)return{xfn:[],other:[]};const n=["contact","acquaintance","friend","met","co-worker","colleague","co-resident","neighbor","child","parent","sibling","spouse","kin","muse","crush","date","sweetheart","me"],o=e.split(/\s+/).filter(Boolean),t=[],l=[];return o.forEach(e=>{n.includes(e)?t.push(e):l.push(e)}),{xfn:t,other:l}}function a(e,n){const o=[...n,...e].filter(Boolean);return[...new Set(o)].join(" ")}function d(e,n){return e.rel?e.rel:e.metadata?.rel?e.metadata.rel:""}const u=({attributes:n,setAttributes:l,name:i})=>{const u=d(n),{xfn:p,other:g}=c(u),f=(e,o,t)=>{let i=[...p];if("radio"===r[e].type){const n=r[e].options.map(e=>e.value);i=i.filter(e=>!n.includes(e)),t&&i.push(o)}else t?i.includes(o)||i.push(o):i=i.filter(e=>e!==o);(e=>{const o=a(e,g);!function(e,n,o){e.hasOwnProperty("rel")?n({rel:o||void 0}):n({metadata:{...e.metadata||{},rel:o||void 0}})}(n,l,o)})(i)},b=["core/button","core/image","core/navigation-link","core/site-logo","core/post-title","core/query-title","core/embed"].includes(i);return(0,s.jsx)(t.InspectorControls,{children:(0,s.jsxs)(o.PanelBody,{title:(0,e.__)("XFN Relationships","link-extension-for-xfn"),initialOpen:b,className:"xfn-inspector-panel",children:[(0,s.jsx)("p",{className:"xfn-panel-description",children:(0,e.__)("Describe your relationship to the people or organizations you link to using XFN (XHTML Friends Network) markup.","link-extension-for-xfn")}),Object.entries(r).map(([n,t])=>{if("radio"===t.type){const l=t.options.find(e=>p.includes(e.value))?.value||"",i=[{label:(0,e.__)("None","link-extension-for-xfn"),value:""},...t.options];return(0,s.jsx)("div",{className:"xfn-category-section",children:(0,s.jsx)(o.RadioControl,{label:t.label,help:t.description,selected:l,options:i,onChange:e=>{f(n,e,""!==e)}})},n)}return(0,s.jsxs)("div",{className:"xfn-category-section",children:[(0,s.jsx)("h4",{className:"xfn-category-title",children:t.label}),(0,s.jsx)("p",{className:"xfn-category-help",children:t.description}),t.options.map(e=>(0,s.jsx)(o.CheckboxControl,{label:e.label,checked:p.includes(e.value),onChange:o=>{f(n,e.value,o)}},e.value))]},n)}),p.length>0&&(0,s.jsxs)("div",{className:"xfn-selected-summary",children:[(0,s.jsx)("h4",{children:(0,e.__)("Selected Relationships:","link-extension-for-xfn")}),(0,s.jsx)("div",{className:"xfn-pills",children:p.map(e=>(0,s.jsx)("span",{className:`xfn-pill xfn-pill-${e}`,children:e},e))})]})]})})};let p=[],g=[],f=null,b=null;function x(){setTimeout(()=>{const n=document.querySelector(".block-editor-link-control");if(!n)return;const o=n.querySelector(".block-editor-link-control__tools .components-button");if(!o)return;if("true"!==o.getAttribute("aria-expanded"))return;const t=n.querySelector(".block-editor-link-control__settings");if(!t)return;if(t.querySelector(".xfn-collapsible-section"))return;console.log("[XFN] Attempting to find link value from React...");const l=n,i=Object.keys(l).find(e=>e.startsWith("__react"));if(i){const e=l[i];console.log("[XFN] React instance found:",e);let n=e,o=0;for(;n&&o<10;){if(n.memoizedProps?.value){b=n.memoizedProps.value,f=n.memoizedProps.onChange,window.currentLinkValue=b,window.currentLinkOnChange=f,console.log("[XFN] Found link value:",b),console.log("[XFN] Link value keys:",Object.keys(b)),console.log("[XFN] Link value rel:",b.rel),console.log("[XFN] Found onChange:",f);break}n=n.return||n._owner,o++}}console.log("[XFN] Looking for rel input in link control...");const s=t.querySelectorAll("input");console.log("[XFN] All inputs in settings panel:",s),s.forEach((e,n)=>{console.log(`[XFN] Input ${n}:`,{type:e.type,id:e.id,name:e.name,placeholder:e.placeholder,value:e.value,element:e})});let u=n.querySelector('input[type="text"][placeholder*="rel" i]');if(console.log("[XFN] Try 1 (placeholder*=rel):",u),u||(u=n.querySelector('input[id*="rel" i]'),console.log("[XFN] Try 2 (id*=rel):",u)),!u){const e=t.querySelectorAll('input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"])');console.log("[XFN] Try 3 - text-like inputs in settings:",e),e.length>0&&(u=e[e.length-1])}console.log("[XFN] Final rel input found:",!!u),u&&(console.log("[XFN] Rel input element:",u),console.log("[XFN] Rel input current value:",u.value));let x="";const h=wp.data.select("core/block-editor").getSelectedBlock();if(h&&["core/button","core/image","core/navigation-link","core/site-logo","core/post-title","core/query-title","core/embed"].includes(h.name))x=d(h.attributes,h.name),console.log("[XFN] Got rel from block-level link attributes:",x);else if(b?.url&&h?.attributes?.content){let e=h.attributes.content;if("object"==typeof e&&e.toHTMLString&&(e=e.toHTMLString()),"string"==typeof e&&e.includes(b.url)){const n=(new DOMParser).parseFromString(e,"text/html"),o=Array.from(n.querySelectorAll("a")).find(e=>e.getAttribute("href")===b.url);o&&(x=o.getAttribute("rel")||"",console.log("[XFN] Got rel from existing link in content:",x))}}!x&&b&&b.rel?(x=b.rel,console.log("[XFN] Got rel from link value:",x)):!x&&u&&(x=u.value,console.log("[XFN] Got rel from input:",x));const{xfn:N,other:F}=c(x);p=[...N],g=[...F],console.log("[XFN] Initial XFN values:",p),console.log("[XFN] Initial other values:",g);const m=document.createElement("div");m.className="xfn-collapsible-section",m.innerHTML=function(n){let o=`\n\t\t<button \n\t\t\tclass="xfn-section-toggle components-button is-tertiary" \n\t\t\taria-expanded="false" \n\t\t\ttype="button"\n\t\t>\n\t\t\tXFN ${n.length>0?`<span class="xfn-count-badge">${n.length}</span>`:""}\n\t\t\t<svg class="xfn-chevron" width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">\n\t\t\t\t<path d="M17.5 11.6L12 16l-5.5-4.4.9-1.2L12 14l4.5-3.6 1 1.2z"/>\n\t\t\t</svg>\n\t\t</button>\n\t\t<div class="xfn-section-content" style="display: none;">\n\t\t\t<p class="xfn-section-description">\n\t\t\t\t${(0,e.__)("Describe your relationship to this person or organization","link-extension-for-xfn")}\n\t\t\t</p>\n\t`;return Object.entries(r).forEach(([t,l])=>{if(o+=`<div class="xfn-category" data-category="${t}">`,o+=`<h4>${l.label}</h4>`,"radio"===l.type){const t=l.options.find(e=>n.includes(e.value))?.value||"";o+='<div class="xfn-button-group">',o+=`<button class="components-button is-compact ${""===t?"is-pressed":""}" data-value="">${(0,e.__)("None","link-extension-for-xfn")}</button>`,l.options.forEach(e=>{o+=`<button class="components-button is-compact ${t===e.value?"is-pressed":""}" data-value="${e.value}">${e.label}</button>`}),o+="</div>"}else o+='<div class="xfn-button-group">',l.options.forEach(e=>{const t=n.includes(e.value);o+=`<button class="components-button is-compact ${t?"is-pressed":""}" data-value="${e.value}">${e.label}</button>`}),o+="</div>";o+="</div>"}),n.length>0&&(o+='<div class="xfn-summary">',o+=`<h4>${(0,e.__)("Active Relationships:","link-extension-for-xfn")}</h4>`,o+='<div class="xfn-pills">',n.forEach(e=>{o+=`<span class="xfn-pill xfn-pill-${e}">${e}</span> `}),o+="</div></div>"),o+="</div>",o}(p),t.appendChild(m),function(n,o){const t=n.querySelector(".xfn-section-toggle"),l=n.querySelector(".xfn-section-content"),i=t.querySelector(".xfn-chevron"),s=n.closest(".block-editor-link-control")||document;t.addEventListener("click",e=>{e.preventDefault(),e.stopPropagation();const n=!("true"===t.getAttribute("aria-expanded"));t.setAttribute("aria-expanded",n),l.style.display=n?"block":"none",i.style.transform=n?"rotate(180deg)":"rotate(0deg)"}),n.querySelectorAll(".xfn-button-group .components-button").forEach(l=>{l.addEventListener("click",l=>{l.preventDefault(),l.stopPropagation();const i=l.target.closest(".xfn-category").dataset.category,c=l.target.dataset.value,d=l.target.closest(".xfn-button-group");if("radio"===r[i].type){const e=r[i].options.map(e=>e.value);p=p.filter(n=>!e.includes(n)),c&&p.push(c),d.querySelectorAll(".components-button").forEach(e=>{e.classList.remove("is-pressed")}),l.target.classList.add("is-pressed")}else l.target.classList.contains("is-pressed")?(p=p.filter(e=>e!==c),l.target.classList.remove("is-pressed")):(p.includes(c)||p.push(c),l.target.classList.add("is-pressed"));(()=>{const l=a(p,g);if(console.log("[XFN] Updating XFN values:",{xfnValues:p,otherValues:g,newRel:l}),o){o.value=l,console.log("[XFN] Updated rel input field to:",l);const e=new Event("input",{bubbles:!0});o.dispatchEvent(e);const n=new Event("change",{bubbles:!0});o.dispatchEvent(n)}window.pendingXFNRel=l,window.pendingXFNUrl=b?.url,console.log("[XFN] Stored pending XFN rel:",window.pendingXFNRel),console.log("[XFN] Stored pending XFN url:",window.pendingXFNUrl),b={...b||{},rel:l||""},console.log("[XFN] Stored rel value (will apply on Submit):",b);const i=s.querySelector('.block-editor-link-control__search-submit, button[type="submit"]');i&&(i.removeAttribute("aria-disabled"),i.removeAttribute("disabled"),i.classList.add("xfn-apply-ready")),function(n){let o=n.querySelector(".xfn-summary");if(0===p.length)return void(o&&o.remove());o||(o=document.createElement("div"),o.className="xfn-summary",n.querySelector(".xfn-section-content").appendChild(o));let t=`<h4>${(0,e.__)("Active Relationships:","link-extension-for-xfn")}</h4>`;t+='<div class="xfn-pills">',p.forEach(e=>{t+=`<span class="xfn-pill xfn-pill-${e}">${e}</span> `}),t+="</div>",o.innerHTML=t}(n),function(e){let n=e.querySelector(".xfn-count-badge");0!==p.length?(n||(n=document.createElement("span"),n.className="xfn-count-badge",e.insertBefore(n,e.querySelector(".xfn-chevron"))),n.textContent=p.length):n&&n.remove()}(t)})()})})}(m,u),console.log("[XFN] Looking for Apply button...");const X=n.querySelectorAll("button");console.log("[XFN] All buttons in link control:",X);const w=n.querySelector('.block-editor-link-control__search-submit, button[type="submit"]');w?(console.log("[XFN] Found Apply button (will save XFN on click)"),w.addEventListener("click",e=>{if(console.log("[XFN] ===== Apply button clicked! ====="),console.log("[XFN] Current XFN values:",p),console.log("[XFN] Current link value:",b),p.length>0){const e=a(p,g);console.log("[XFN] Storing XFN rel for post-link-creation:",e),window.pendingXFNRel=e,window.pendingXFNUrl=b?.url,console.log("[XFN] Scheduling XFN application attempts..."),setTimeout(()=>{console.log("[XFN] Attempt 1 (100ms)..."),k()},100),setTimeout(()=>{console.log("[XFN] Attempt 2 (300ms)..."),k()},300),setTimeout(()=>{console.log("[XFN] Attempt 3 (500ms)..."),k()},500),setTimeout(()=>{console.log("[XFN] Attempt 4 (1000ms)..."),k()},1e3)}else console.log("[XFN] No XFN values selected, skipping");o&&"true"===o.getAttribute("aria-expanded")&&setTimeout(()=>o.click(),150)},!0),console.log("[XFN] Apply button interceptor attached")):console.warn("[XFN] Apply button not found!")},100)}function k(){if(console.log("[XFN] ===== Applying XFN to created link ====="),console.log("[XFN] Pending XFN rel:",window.pendingXFNRel),console.log("[XFN] Pending XFN url:",window.pendingXFNUrl),!window.pendingXFNRel||!window.pendingXFNUrl)return console.log("[XFN] No pending XFN data to apply"),!1;const e=wp.data.select("core/block-editor").getSelectedBlock();if(!e)return console.log("[XFN] No selected block found"),!1;if(console.log("[XFN] Selected block:",e.name),console.log("[XFN] Selected block clientId:",e.clientId),console.log("[XFN] Selected block attributes:",e.attributes),console.log("[XFN] Block innerBlocks:",e.innerBlocks),["core/button","core/image","core/navigation-link","core/site-logo","core/post-title","core/query-title","core/embed"].includes(e.name)){console.log("[XFN] This is a block-level link, updating rel attribute directly...");const n=d(e.attributes,e.name);console.log("[XFN] Existing rel:",n);const{other:o}=c(n);console.log("[XFN] Existing other values:",o);const{xfn:t}=c(window.pendingXFNRel);console.log("[XFN] Pending XFN values:",t);const l=a(t,o);if(console.log("[XFN] New combined rel:",l),e.attributes.hasOwnProperty("rel"))wp.data.dispatch("core/block-editor").updateBlockAttributes(e.clientId,{rel:l||void 0}),console.log("[XFN] ✓ Updated rel attribute on block");else{const n=e.attributes.metadata||{};wp.data.dispatch("core/block-editor").updateBlockAttributes(e.clientId,{metadata:{...n,rel:l||void 0}}),console.log("[XFN] ✓ Updated metadata.rel attribute on block")}if(window.currentLinkOnChange&&"function"==typeof window.currentLinkOnChange)try{const e={...window.currentLinkValue||{},rel:l||""};window.currentLinkOnChange(e),console.log("[XFN] ✓ Also called onChange with updated rel")}catch(e){console.warn("[XFN] Could not call onChange:",e)}return window.pendingXFNRel=null,window.pendingXFNUrl=null,console.log("[XFN] ✓✓✓ Block-level link updated successfully! ✓✓✓"),!0}let n=e.attributes.content;if(console.log("[XFN] Block content:",n),console.log("[XFN] Block content type:",typeof n),n&&"object"==typeof n&&n.toHTMLString&&(console.log("[XFN] Converting RichTextData to HTML string..."),n=n.toHTMLString(),console.log("[XFN] Converted content:",n)),!n||"string"!=typeof n)return console.warn("[XFN] Block has no string content or unable to convert to string"),!1;const o=n.includes(window.pendingXFNUrl);if(console.log("[XFN] URL in content?",o),!o)return console.warn("[XFN] Pending URL not found in block content"),console.log("[XFN] Looking for:",window.pendingXFNUrl),console.log("[XFN] In content:",n),!1;console.log("[XFN] Found URL in block content, attempting to update using proper WordPress approach...");try{const{xfn:o,other:t}=c(window.pendingXFNRel),l=(new DOMParser).parseFromString(n,"text/html"),i=l.querySelectorAll("a");let s=!1;if(i.forEach(e=>{if(e.getAttribute("href")===window.pendingXFNUrl){const n=e.getAttribute("rel")||"",{other:l}=c(n),i=a(o,l.length?l:t);console.log("[XFN] Setting rel attribute:",i),e.setAttribute("rel",i),s=!0}}),s){const n=l.body.innerHTML;return console.log("[XFN] Updating block with new content..."),wp.data.dispatch("core/block-editor").updateBlockAttributes(e.clientId,{content:n}),console.log("[XFN] ✓ Block content updated"),window.pendingXFNRel=null,window.pendingXFNUrl=null,setTimeout(()=>{const n=wp.data.select("core/block-editor").getBlock(e.clientId);console.log("[XFN] Verification - Current content:",n?.attributes?.content)},100),!0}}catch(e){console.error("[XFN] Error updating link:",e)}return console.warn("[XFN] Could not update link"),!1}const h=(0,l.createHigherOrderComponent)(e=>n=>{const{attributes:o,name:t}=n,l=window.linkexfoData?.settings||{enable_inspector_controls:!1,enable_floating_toolbar:!1};return(["core/button","core/image","core/navigation-link","core/site-logo","core/post-title","core/query-title","core/embed"].includes(t)||o.hasOwnProperty("url")||o.hasOwnProperty("href")||o.hasOwnProperty("linkDestination"))&&l.enable_inspector_controls?(d(o),(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(e,{...n}),(0,s.jsx)(u,{...n})]})):(0,s.jsx)(e,{...n})},"withXFNControls");window.linkexfoData?.settings?.enable_inspector_controls&&((0,n.addFilter)("editor.BlockEdit","xfn-link-extension/with-xfn-controls",h),console.log("[XFN] Inspector Controls enabled")),(0,n.addFilter)("blocks.getSaveContent.extraProps","xfn-link-extension/add-rel-to-links",(e,n,o)=>(console.log("[XFN] getSaveContent filter called for:",n.name),p.length>0&&console.log("[XFN] Injecting XFN values into saved content:",p),e)),"undefined"!=typeof document&&(console.log("[XFN] Starting XFN monitoring in 1 second..."),setTimeout(()=>{console.log("[XFN] XFN monitoring started!"),new MutationObserver(e=>{e.forEach(e=>{"childList"===e.type&&Array.from(e.addedNodes).forEach(e=>{e.nodeType===Node.ELEMENT_NODE&&((e.classList?.contains("block-editor-link-control")||e.querySelector?.(".block-editor-link-control"))&&x(),(e.classList?.contains("block-editor-link-control__settings")||e.querySelector?.(".block-editor-link-control__settings"))&&x())}),"attributes"===e.type&&"aria-expanded"===e.attributeName&&x()})}).observe(document.body,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["aria-expanded"]}),document.addEventListener("click",e=>{e.target.closest(".block-editor-link-control__tools .components-button")&&setTimeout(x,50)})},1e3)),console.log("%c[XFN] Link Extension loaded successfully!","color: #00a32a; font-weight: bold; font-size: 14px;"),console.log("[XFN] Controls will appear in:");const N=window.linkexfoData?.settings||{enable_inspector_controls:!1,enable_floating_toolbar:!1};N.enable_inspector_controls?console.log("[XFN] ✓ Inspector Controls for link blocks (ENABLED)"):console.log("[XFN] ✗ Inspector Controls for link blocks (DISABLED - enable in Settings > Link Extension for XFN)"),N.enable_floating_toolbar?console.log("[XFN] ✓ Floating toolbar for link blocks (ENABLED)"):console.log("[XFN] ✗ Floating toolbar for link blocks (DISABLED - enable in Settings > Link Extension for XFN)"),console.log("[XFN] ✓ Collapsible XFN section in Link Advanced Panel (ALWAYS ENABLED)")})();
  • link-extension-for-xfn/trunk/link-extension-for-xfn.php

    r3415433 r3415636  
    654654    return XFN_Link_Extension::sanitize_rel_attribute( $rel_value );
    655655}
     656
     657/**
     658 * Filter embed block output to add XFN rel attributes
     659 *
     660 * Modifies the rendered HTML of embed blocks to include XFN relationships
     661 * stored in block metadata. Adds rel attributes to any links found in the
     662 * embed output, or adds a data-rel attribute to the figure element.
     663 *
     664 * @since 1.0.2
     665 * @param string $block_content The block content about to be rendered
     666 * @param array  $block The full block, including name and attributes
     667 * @return string Modified block content with XFN attributes
     668 */
     669function xfn_render_embed_block( $block_content, $block ) {
     670    // Only process embed blocks
     671    if ( 'core/embed' !== $block['blockName'] ) {
     672        return $block_content;
     673    }
     674
     675    // Check if block has XFN metadata
     676    if ( empty( $block['attrs']['metadata']['rel'] ) ) {
     677        return $block_content;
     678    }
     679
     680    $rel_value = $block['attrs']['metadata']['rel'];
     681
     682    // Sanitize the rel value
     683    $rel_value = XFN_Link_Extension::sanitize_rel_attribute( $rel_value );
     684
     685    if ( empty( $rel_value ) ) {
     686        return $block_content;
     687    }
     688
     689    // Try to find and modify any existing links in the embed output
     690    if ( preg_match( '/<a\s+([^>]*?)>/', $block_content ) ) {
     691        // Embed contains a link - add rel to it
     692        $block_content = preg_replace_callback(
     693            '/<a\s+([^>]*?)>/',
     694            function( $matches ) use ( $rel_value ) {
     695                $attrs = $matches[1];
     696
     697                // Check if rel already exists
     698                if ( preg_match( '/rel=["\']([^"\']*)["\']/', $attrs, $rel_match ) ) {
     699                    // Combine existing rel with XFN
     700                    $existing_rel = $rel_match[1];
     701                    $parsed = XFN_Link_Extension::parse_rel_attribute( $existing_rel );
     702                    $new_xfn = XFN_Link_Extension::parse_rel_attribute( $rel_value );
     703                    $combined = XFN_Link_Extension::combine_rel_values( $new_xfn['xfn'], $parsed['other'] );
     704
     705                    // Replace existing rel
     706                    $attrs = preg_replace(
     707                        '/rel=["\'][^"\']*["\']/',
     708                        'rel="' . esc_attr( $combined ) . '"',
     709                        $attrs
     710                    );
     711                } else {
     712                    // Add new rel attribute
     713                    $attrs .= ' rel="' . esc_attr( $rel_value ) . '"';
     714                }
     715
     716                return '<a ' . $attrs . '>';
     717            },
     718            $block_content
     719        );
     720    } else {
     721        // No link in embed output - add data-xfn-rel to figure element for semantic purposes
     722        $block_content = preg_replace(
     723            '/<figure\s+([^>]*?)class="([^"]*)"([^>]*)>/',
     724            '<figure $1class="$2"$3 data-xfn-rel="' . esc_attr( $rel_value ) . '">',
     725            $block_content
     726        );
     727    }
     728
     729    return $block_content;
     730}
     731add_filter( 'render_block', 'xfn_render_embed_block', 10, 2 );
  • link-extension-for-xfn/trunk/readme.txt

    r3415433 r3415636  
    3535
    3636* **Link Advanced Panel** (Always enabled): Collapsible XFN section in link popovers for inline links - works immediately after installation
    37 * **Inspector Controls** (Optional): Panel in the block sidebar for Button, Image, and Navigation blocks - enable in Settings → Link Extension for XFN
     37* **Inspector Controls** (Optional): Panel in the block sidebar for Button, Image, Navigation, and Embed blocks - enable in Settings → Link Extension for XFN
    3838
    3939### Seamless Integration with WordPress
    4040The plugin extends the existing link interfaces without disrupting your workflow:
    4141
    42 * Works with Paragraph, Button, Navigation, List, and all other link-supporting blocks
     42* Works with Paragraph, Button, Navigation, List, Embed, and all other link-supporting blocks
    4343* Compatible with both Post Editor and Site Editor
    4444* Preserves existing rel attributes (nofollow, noopener, noreferrer)
     
    6565After installation, XFN options are immediately available for inline links (links within paragraphs, headings, lists).
    6666
    67 To use XFN with Button, Image, and Navigation blocks, go to **Settings → Link Extension for XFN** and enable **Inspector Controls**.
     67To use XFN with Button, Image, Navigation, and Embed blocks, go to **Settings → Link Extension for XFN** and enable **Inspector Controls**.
    6868
    6969### Method 1: Using Link Advanced Panel (Always Available)
     
    7777### Method 2: Using Inspector Controls (Enable in Settings)
    78781. Go to Settings → Link Extension for XFN and enable Inspector Controls
    79 2. Select a Button, Image, or Navigation block
     792. Select a Button, Image, Navigation, or Embed block
    80803. Look in the right sidebar - "XFN Relationships" panel opens by default
    81814. Select relationships using radio buttons and checkboxes organized by category
     
    127127Enhance your site navigation with relationship context using the Inspector Controls. Mark links to your social profiles, partner sites, or affiliated organizations with the organized collapsible interface.
    128128
     129### Embed Block
     130Add semantic meaning to embedded content from YouTube, Twitter, and other platforms. Use the Inspector Controls to indicate relationships with embedded content creators, marking videos from colleagues, friends, or your own channels. Perfect for blogrolls, resource pages, and content aggregation.
     131
    129132### Paragraph Block (Inline Links)
    130133For inline links within paragraph content, use the collapsible XFN section in the link popover's Advanced area to add relationship context without overwhelming the interface.
     
    203206XFN controls are available in two locations, both featuring collapsible interfaces:
    2042071. **Link Advanced Panel** (Always available): In the Advanced section of inline link popovers as a collapsible "XFN" section
    205 2. **Inspector Controls** (Enable in Settings): In the block settings sidebar under "XFN Relationships" panel for Button, Image, and Navigation blocks
     2082. **Inspector Controls** (Enable in Settings): In the block settings sidebar under "XFN Relationships" panel for Button, Image, Navigation, and Embed blocks
    206209
    207210### Why use a collapsible interface?
     
    3483513. No configuration required - XFN options will immediately appear in:
    349352   - **Link Advanced Panel** (Always available): Collapsible XFN section in the Advanced area of link popovers for inline links
    350    - **Inspector Controls** (Optional): Panel in the block sidebar for Button, Image, and Navigation blocks - enable in Settings → Link Extension for XFN
     353   - **Inspector Controls** (Optional): Panel in the block sidebar for Button, Image, Navigation, and Embed blocks - enable in Settings → Link Extension for XFN
    3513544. Start adding relationship context to your links using the intuitive collapsible interface
    352355
  • link-extension-for-xfn/trunk/src/index.js

    r3415429 r3415636  
    505505        'core/post-title',
    506506        'core/query-title',
     507        'core/embed',
    507508    ];
    508509    const shouldBeOpenByDefault = blockLevelLinks.includes( name );
     
    770771            'core/post-title',
    771772            'core/query-title',
     773            'core/embed',
    772774        ];
    773775
     
    12141216        'core/post-title',
    12151217        'core/query-title',
     1218        'core/embed',
    12161219    ];
    12171220
     
    14511454            'core/post-title',
    14521455            'core/query-title',
     1456            'core/embed',
    14531457        ];
    14541458
Note: See TracChangeset for help on using the changeset viewer.