updated plugin ActivityPub version 8.3.0

This commit is contained in:
2026-06-03 21:28:46 +00:00
committed by Gitium
parent a4b78ec277
commit 6fe182458a
340 changed files with 43232 additions and 7568 deletions

View File

@ -1,27 +1,66 @@
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"name": "activitypub/reactions",
"apiVersion": 2,
"version": "1.0.0",
"apiVersion": 3,
"version": "8.3.0",
"title": "Fediverse Reactions",
"category": "widgets",
"icon": "heart",
"description": "Display Fediverse likes and reposts",
"supports": {
"html": false,
"align": true,
"layout": {
"default": {
"type": "constrained",
"orientation": "vertical",
"justifyContent": "center"
}
"keywords": [
"fediverse",
"activitypub",
"likes",
"reposts"
],
"description": "Display Fediverse likes and reposts for your posts.",
"example": {
"attributes": {
"className": "is-style-facepile"
}
},
"styles": [
{
"name": "facepile",
"label": "Facepile",
"isDefault": true
},
{
"name": "compact",
"label": "Compact"
}
],
"attributes": {
"title": {
"displayStyle": {
"type": "string",
"default": "Fediverse reactions"
"default": "facepile"
},
"showActions": {
"type": "boolean",
"default": false
}
},
"supports": {
"align": [
"wide",
"full"
],
"color": {
"gradients": true
},
"__experimentalBorder": {
"radius": true,
"width": true,
"color": true,
"style": true
},
"html": false,
"interactivity": true,
"shadow": true,
"typography": {
"fontSize": true,
"__experimentalDefaultControls": {
"fontSize": true
}
}
},
"blockHooks": {
@ -29,9 +68,9 @@
},
"textdomain": "activitypub",
"editorScript": "file:./index.js",
"style": [
"file:./style-index.css",
"wp-components"
],
"viewScript": "file:./view.js"
"style": "file:./style-index.css",
"viewStyle": "file:./view.css",
"viewScriptModule": "file:./view.js",
"viewScript": "wp-api-fetch",
"render": "file:./render.php"
}

View File

@ -1 +1 @@
<?php return array('dependencies' => array('react', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n'), 'version' => '32631215c76c36b38e5e');
<?php return array('dependencies' => array('react-jsx-runtime', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n'), 'version' => '1e13568c338d5be171c1');

View File

@ -1,3 +1,4 @@
(()=>{"use strict";var e,t={373:(e,t,a)=>{const n=window.wp.blocks,r=window.React,l=window.wp.blockEditor,o=window.wp.element,s=window.wp.i18n,i=window.wp.components,c=window.wp.apiFetch;var u=a.n(c);function m(){return window._activityPubOptions||{}}const p=({reactions:e})=>{const{defaultAvatarUrl:t}=m(),[a,n]=(0,o.useState)(new Set),[l,s]=(0,o.useState)(new Map),i=(0,o.useRef)([]),c=()=>{i.current.forEach((e=>clearTimeout(e))),i.current=[]},u=(t,a)=>{c();const r=100,l=e.length;a&&s((e=>{const a=new Map(e);return a.set(t,"clockwise"),a}));const o=e=>{const o="right"===e,c=o?l-1:0,u=o?1:-1;for(let e=o?t:t-1;o?e<=c:e>=c;e+=u){const l=Math.abs(e-t),o=setTimeout((()=>{n((t=>{const n=new Set(t);return a?n.add(e):n.delete(e),n})),a&&e!==t&&s((t=>{const a=new Map(t),n=e-u,r=a.get(n);return a.set(e,"clockwise"===r?"counter":"clockwise"),a}))}),l*r);i.current.push(o)}};if(o("right"),o("left"),!a){const e=Math.max((l-t)*r,t*r),a=setTimeout((()=>{s(new Map)}),e+r);i.current.push(a)}};return(0,o.useEffect)((()=>()=>c()),[]),(0,r.createElement)("ul",{className:"reaction-avatars"},e.map(((e,n)=>{const o=l.get(n),s=["reaction-avatar",a.has(n)?"wave-active":"",o?`rotate-${o}`:""].filter(Boolean).join(" "),i=e.avatar||t;return(0,r.createElement)("li",{key:n},(0,r.createElement)("a",{href:e.url,target:"_blank",rel:"noopener noreferrer",onMouseEnter:()=>u(n,!0),onMouseLeave:()=>u(n,!1)},(0,r.createElement)("img",{src:i,alt:e.name,className:s,width:"32",height:"32"})))})))},f=({reactions:e,type:t})=>(0,r.createElement)("ul",{className:"activitypub-reaction-list"},e.map(((e,t)=>(0,r.createElement)("li",{key:t},(0,r.createElement)("a",{href:e.url,className:"reaction-item",target:"_blank",rel:"noopener noreferrer"},(0,r.createElement)("img",{src:e.avatar,alt:e.name,width:"32",height:"32"}),(0,r.createElement)("span",null,e.name)))))),h=({items:e,label:t})=>{const[a,n]=(0,o.useState)(!1),[l,s]=(0,o.useState)(null),[c,u]=(0,o.useState)(e.length),m=(0,o.useRef)(null);(0,o.useEffect)((()=>{if(!m.current)return;const t=()=>{const t=m.current;if(!t)return;const a=t.offsetWidth-(l?.offsetWidth||0)-12,n=Math.max(1,Math.floor((a-32)/22));u(Math.min(n,e.length))};t();const a=new ResizeObserver(t);return a.observe(m.current),()=>{a.disconnect()}}),[l,e.length]);const h=e.slice(0,c);return(0,r.createElement)("div",{className:"reaction-group",ref:m},(0,r.createElement)(p,{reactions:h}),(0,r.createElement)(i.Button,{ref:s,className:"reaction-label is-link",onClick:()=>n(!a),"aria-expanded":a},t),a&&l&&(0,r.createElement)(i.Popover,{anchor:l,onClose:()=>n(!1)},(0,r.createElement)(f,{reactions:e})))};function d({title:e="",postId:t=null,reactions:a=null,titleComponent:n=null}){const{namespace:l}=m(),[s,i]=(0,o.useState)(a),[c,p]=(0,o.useState)(!a);return(0,o.useEffect)((()=>{if(a)return i(a),void p(!1);t?(p(!0),u()({path:`/${l}/posts/${t}/reactions`}).then((e=>{i(e),p(!1)})).catch((()=>p(!1)))):p(!1)}),[t,a]),c?null:s&&Object.values(s).some((e=>e.items?.length>0))?(0,r.createElement)("div",{className:"activitypub-reactions"},n||e&&(0,r.createElement)("h6",null,e),Object.entries(s).map((([e,t])=>t.items?.length?(0,r.createElement)(h,{key:e,items:t.items,label:t.label}):null))):null}const v=e=>{const t=["#FF6B6B","#4ECDC4","#45B7D1","#96CEB4","#FFEEAD","#D4A5A5","#9B59B6","#3498DB","#E67E22"],a=(()=>{const e=["Bouncy","Cosmic","Dancing","Fluffy","Giggly","Hoppy","Jazzy","Magical","Nifty","Perky","Quirky","Sparkly","Twirly","Wiggly","Zippy"],t=["Badger","Capybara","Dolphin","Echidna","Flamingo","Giraffe","Hedgehog","Iguana","Jellyfish","Koala","Lemur","Manatee","Narwhal","Octopus","Penguin"];return`${e[Math.floor(Math.random()*e.length)]} ${t[Math.floor(Math.random()*t.length)]}`})(),n=t[Math.floor(Math.random()*t.length)],r=a.charAt(0),l=document.createElement("canvas");l.width=64,l.height=64;const o=l.getContext("2d");return o.fillStyle=n,o.beginPath(),o.arc(32,32,32,0,2*Math.PI),o.fill(),o.fillStyle="#FFFFFF",o.font="32px sans-serif",o.textAlign="center",o.textBaseline="middle",o.fillText(r,32,32),{name:a,url:"#",avatar:l.toDataURL()}},g=JSON.parse('{"UU":"activitypub/reactions"}');(0,n.registerBlockType)(g.UU,{edit:function({attributes:e,setAttributes:t,__unstableLayoutClassNames:a}){const n=(0,l.useBlockProps)({className:a}),[i]=(0,o.useState)({likes:{label:(0,s.sprintf)(/* translators: %d: Number of likes */ /* translators: %d: Number of likes */
(0,s._x)("%d likes","number of likes","activitypub"),9),items:Array.from({length:9},((e,t)=>v()))},reposts:{label:(0,s.sprintf)(/* translators: %d: Number of reposts */ /* translators: %d: Number of reposts */
(0,s._x)("%d reposts","number of reposts","activitypub"),6),items:Array.from({length:6},((e,t)=>v()))}}),c=(0,r.createElement)(l.RichText,{tagName:"h6",value:e.title,onChange:e=>t({title:e}),placeholder:(0,s.__)("Fediverse Reactions","activitypub"),disableLineBreaks:!0,allowedFormats:[]});return(0,r.createElement)("div",{...n},(0,r.createElement)(d,{titleComponent:c,reactions:i}))}})}},a={};function n(e){var r=a[e];if(void 0!==r)return r.exports;var l=a[e]={exports:{}};return t[e](l,l.exports,n),l.exports}n.m=t,e=[],n.O=(t,a,r,l)=>{if(!a){var o=1/0;for(u=0;u<e.length;u++){a=e[u][0],r=e[u][1],l=e[u][2];for(var s=!0,i=0;i<a.length;i++)(!1&l||o>=l)&&Object.keys(n.O).every((e=>n.O[e](a[i])))?a.splice(i--,1):(s=!1,l<o&&(o=l));if(s){e.splice(u--,1);var c=r();void 0!==c&&(t=c)}}return t}l=l||0;for(var u=e.length;u>0&&e[u-1][2]>l;u--)e[u]=e[u-1];e[u]=[a,r,l]},n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var a in t)n.o(t,a)&&!n.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var e={608:0,104:0};n.O.j=t=>0===e[t];var t=(t,a)=>{var r,l,o=a[0],s=a[1],i=a[2],c=0;if(o.some((t=>0!==e[t]))){for(r in s)n.o(s,r)&&(n.m[r]=s[r]);if(i)var u=i(n)}for(t&&t(a);c<o.length;c++)l=o[c],n.o(e,l)&&e[l]&&e[l][0](),e[l]=0;return n.O(u)},a=self.webpackChunkwordpress_activitypub=self.webpackChunkwordpress_activitypub||[];a.forEach(t.bind(null,0)),a.push=t.bind(null,a.push.bind(a))})();var r=n.O(void 0,[104],(()=>n(373)));r=n.O(r)})();
(()=>{"use strict";var e,t={2091(e,t,s){const i=window.wp.blocks,r=window.wp.blockEditor,a=window.ReactJSXRuntime,n=[{attributes:{},supports:{html:!1,align:!0,layout:{default:{type:"constrained",orientation:"vertical",justifyContent:"center"}}},save:()=>(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(r.InnerBlocks.Content,{}),(0,a.jsx)("div",{className:"activitypub-reactions-block"})]})},{attributes:{title:{type:"string",default:"Fediverse reactions"}},supports:{html:!1,align:!0,layout:{default:{type:"constrained",orientation:"vertical",justifyContent:"center"}}},save:()=>null,isEligible:({title:e})=>!!e,migrate:({title:e,...t})=>[t,[(0,i.createBlock)("core/heading",{content:e,level:6})]]}];function o(e){var t,s,i="";if("string"==typeof e||"number"==typeof e)i+=e;else if("object"==typeof e)if(Array.isArray(e)){var r=e.length;for(t=0;t<r;t++)e[t]&&(s=o(e[t]))&&(i&&(i+=" "),i+=s)}else for(s in e)e[s]&&(i&&(i+=" "),i+=s);return i}const l=function(){for(var e,t,s=0,i="",r=arguments.length;s<r;s++)(e=arguments[s])&&(t=o(e))&&(i&&(i+=" "),i+=t);return i},c=window.wp.components,p=window.wp.i18n,u=window.wp.data,d=window.wp.element,f=window.wp.apiFetch;var v=s.n(f);function y(){return window._activityPubOptions||{}}const m={like:(0,p.__)("Like","activitypub"),likes:(0,p.__)("Like","activitypub"),repost:(0,p.__)("Repost","activitypub"),reposts:(0,p.__)("Repost","activitypub"),quote:(0,p.__)("Quote","activitypub"),quotes:(0,p.__)("Quote","activitypub")},h=({reactions:e,displayStyle:t})=>{const{defaultAvatarUrl:s}=y();return"compact"===t?null:(0,a.jsx)("ul",{className:"reaction-avatars",children:e.map((e,t)=>{const i=["reaction-avatar"].filter(Boolean).join(" "),r=e.avatar||s;return(0,a.jsx)("li",{children:(0,a.jsx)("a",{href:e.url,target:"_blank",rel:"noopener noreferrer",children:(0,a.jsx)("img",{src:r,alt:e.name,className:i,width:"32",height:"32",onError:e=>{e.target.src=s}})})},t)})})},b=({reactions:e,displayStyle:t})=>{const{defaultAvatarUrl:s}=y();return(0,a.jsx)("ul",{className:"reactions-list",children:e.map((e,i)=>{const r=e.avatar||s;return(0,a.jsx)("li",{className:"reaction-item",children:(0,a.jsxs)("a",{href:e.url,className:"reaction-item",target:"_blank",rel:"noopener noreferrer",children:["facepile"===t&&(0,a.jsx)("img",{src:r,alt:e.name,width:"32",height:"32",onError:e=>{e.target.src=s}}),(0,a.jsx)("span",{className:"reaction-name",children:e.name})]})},i)})})},w=({items:e,label:t,displayStyle:s,showActions:i,actionLabel:r})=>{const[n,o]=(0,d.useState)(!1),[l,p]=(0,d.useState)(null),u=(0,d.useRef)(null),f=e.slice(0,20);return(0,a.jsxs)("div",{className:"reaction-group",ref:u,children:[i&&r&&(0,a.jsx)("button",{className:"reaction-action-button wp-element-button",type:"button",disabled:!0,children:r}),(0,a.jsx)(h,{reactions:f,displayStyle:s}),(0,a.jsx)(c.Button,{ref:p,className:"reaction-label is-link",onClick:()=>o(!n),"aria-expanded":n,children:t}),n&&l&&(0,a.jsx)(c.Popover,{anchor:l,onClose:()=>o(!1),className:"activitypub-popover",children:(0,a.jsx)(b,{reactions:e,displayStyle:s})})]})};function g({postId:e=null,reactions:t=null,fallbackReactions:s=null,displayStyle:i="facepile",showActions:r=!1}){const{namespace:n}=y(),[o,l]=(0,d.useState)(t),[c,p]=(0,d.useState)(!t),u=(0,d.useCallback)(()=>{s&&l(s),p(!1)},[s]);return(0,d.useEffect)(()=>{if(t)return l(t),void p(!1);e&&"number"==typeof e?(p(!0),v()({path:`/${n}/posts/${e}/reactions`}).then(e=>{const t=Object.values(e).some(e=>e.items?.length>0);l(!t&&s?s:e),p(!1)}).catch(u)):u()},[e,t,s,n,u]),c?null:o&&Object.values(o).some(e=>e.items?.length>0)?(0,a.jsx)("div",{className:"activitypub-reactions",children:Object.entries(o).map(([e,t])=>t.items?.length?(0,a.jsx)(w,{items:t.items,label:t.label,displayStyle:i,showActions:r,actionLabel:m[e]},e):null)}):null}const x=(e,t,s,i)=>Array.from({length:e},(e,r)=>({name:`${t} ${r+1}`,url:"#",avatar:`data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Ccircle cx='32' cy='32' r='32' fill='%23${i[r%i.length]}'/%3E%3Ctext x='32' y='38' font-family='sans-serif' font-size='24' fill='white' text-anchor='middle'%3E${String.fromCharCode(s+r)}%3C/text%3E%3C/svg%3E`})),j=["FF6B6B","4ECDC4","45B7D1","96CEB4","D4A5A5","9B59B6","3498DB","E67E22"],k={likes:{label:(0,p.sprintf)(/* translators: %d: Number of likes */ /* translators: %d: Number of likes */
(0,p._x)("%d likes","number of likes","activitypub"),9),items:x(9,"User",65,j)},reposts:{label:(0,p.sprintf)(/* translators: %d: Number of reposts */ /* translators: %d: Number of reposts */
(0,p._x)("%d reposts","number of reposts","activitypub"),6),items:x(6,"Reposter",82,j)},quotes:{label:(0,p.sprintf)(/* translators: %d: Number of quotes */ /* translators: %d: Number of quotes */
(0,p._x)("%d quotes","number of quotes","activitypub"),7),items:x(7,"Quoter",81,j)}},_=JSON.parse('{"$schema":"https://schemas.wp.org/trunk/block.json","name":"activitypub/reactions","apiVersion":3,"version":"8.2.1","title":"Fediverse Reactions","category":"widgets","icon":"heart","keywords":["fediverse","activitypub","likes","reposts"],"description":"Display Fediverse likes and reposts for your posts.","example":{"attributes":{"className":"is-style-facepile"}},"styles":[{"name":"facepile","label":"Facepile","isDefault":true},{"name":"compact","label":"Compact"}],"attributes":{"displayStyle":{"type":"string","default":"facepile"},"showActions":{"type":"boolean","default":false}},"supports":{"align":["wide","full"],"color":{"gradients":true},"__experimentalBorder":{"radius":true,"width":true,"color":true,"style":true},"html":false,"interactivity":true,"shadow":true,"typography":{"fontSize":true,"__experimentalDefaultControls":{"fontSize":true}}},"blockHooks":{"core/post-content":"after"},"textdomain":"activitypub","editorScript":"file:./index.js","style":"file:./style-index.css","viewStyle":"file:./view.css","viewScriptModule":"file:./view.js","viewScript":"wp-api-fetch","render":"file:./render.php"}');(0,i.registerBlockType)(_,{deprecated:n,edit:function({attributes:e,setAttributes:t}){const{className:s="",displayStyle:i="facepile",showActions:n=!1}=e,o=(0,r.useBlockProps)(),{getCurrentPostId:f}=(0,u.select)("core/editor"),{showAvatars:v=!0}=y(),m=(0,d.useRef)(!1);(0,d.useEffect)(()=>{if(m.current)return;m.current=!0;const e=s?.includes("is-style-");if(!e){const e=v?"facepile":"compact";t({className:l(s,`is-style-${e}`),displayStyle:e})}},[s,v,t]);const h=s?.includes("is-style-compact")?"compact":"facepile";(0,d.useEffect)(()=>{h!==i&&t({displayStyle:h})},[h,i,t]);const b=[["core/heading",{level:6,placeholder:(0,p.__)("Fediverse Reactions","activitypub"),content:(0,p.__)("Fediverse Reactions","activitypub")}]];return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(r.InspectorControls,{children:(0,a.jsx)(c.PanelBody,{title:(0,p.__)("Action Buttons","activitypub"),children:(0,a.jsx)(c.ToggleControl,{__nextHasNoMarginBottom:!0,label:(0,p.__)("Show action buttons","activitypub"),help:(0,p.__)("Display Like and Boost buttons so visitors can interact from their Fediverse server.","activitypub"),checked:n,onChange:e=>t({showActions:e})})})}),(0,a.jsxs)("div",{...o,children:[(0,a.jsx)(r.InnerBlocks,{template:b,allowedBlocks:["core/heading"],templateLock:"all",renderAppender:!1}),(0,a.jsx)(g,{postId:f(),fallbackReactions:k,displayStyle:i,showActions:n})]})]})},save:function(){return(0,a.jsx)("div",{...r.useBlockProps.save(),children:(0,a.jsx)(r.InnerBlocks.Content,{})})}})}},s={};function i(e){var r=s[e];if(void 0!==r)return r.exports;var a=s[e]={exports:{}};return t[e](a,a.exports,i),a.exports}i.m=t,e=[],i.O=(t,s,r,a)=>{if(!s){var n=1/0;for(p=0;p<e.length;p++){for(var[s,r,a]=e[p],o=!0,l=0;l<s.length;l++)(!1&a||n>=a)&&Object.keys(i.O).every(e=>i.O[e](s[l]))?s.splice(l--,1):(o=!1,a<n&&(n=a));if(o){e.splice(p--,1);var c=r();void 0!==c&&(t=c)}}return t}a=a||0;for(var p=e.length;p>0&&e[p-1][2]>a;p--)e[p]=e[p-1];e[p]=[s,r,a]},i.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return i.d(t,{a:t}),t},i.d=(e,t)=>{for(var s in t)i.o(t,s)&&!i.o(e,s)&&Object.defineProperty(e,s,{enumerable:!0,get:t[s]})},i.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var e={608:0,104:0};i.O.j=t=>0===e[t];var t=(t,s)=>{var r,a,[n,o,l]=s,c=0;if(n.some(t=>0!==e[t])){for(r in o)i.o(o,r)&&(i.m[r]=o[r]);if(l)var p=l(i)}for(t&&t(s);c<n.length;c++)a=n[c],i.o(e,a)&&e[a]&&e[a][0](),e[a]=0;return i.O(p)},s=globalThis.webpackChunkwordpress_activitypub=globalThis.webpackChunkwordpress_activitypub||[];s.forEach(t.bind(null,0)),s.push=t.bind(null,s.push.bind(s))})();var r=i.O(void 0,[104],()=>i(2091));r=i.O(r)})();

View File

@ -0,0 +1,418 @@
<?php
/**
* Server-side rendering of the `activitypub/reactions` block.
*
* @package ActivityPub
*/
use Activitypub\Blocks;
use Activitypub\Comment;
use function Activitypub\get_post_id;
use function Activitypub\is_activitypub_request;
use function Activitypub\is_post_publicly_queryable;
if ( is_activitypub_request() || is_feed() ) {
return;
}
// Get the default display style based on WordPress avatar settings.
$default_display_style = get_option( 'show_avatars', true ) ? 'facepile' : 'compact';
/* @var array $attributes Block attributes. */
$attributes = wp_parse_args(
$attributes,
array(
'align' => null,
'displayStyle' => $default_display_style,
'showActions' => false,
)
);
/* @var \WP_Block $block Current block. */
$block = $block ?? '';
/* @var string $content Block content. */
$content = $content ?? '';
if ( empty( $content ) ) {
// Fallback for v1.0.0 blocks.
$_title = $attributes['title'] ?? __( 'Fediverse Reactions', 'activitypub' );
$content = '<h6 class="wp-block-heading">' . esc_html( $_title ) . '</h6>';
unset( $attributes['title'] );
} else {
$content = implode( PHP_EOL, wp_list_pluck( $block->parsed_block['innerBlocks'], 'innerHTML' ) );
// Hide empty headings.
if ( empty( wp_strip_all_tags( $content ) ) ) {
$content = '';
}
}
// Get the Post ID from attributes or use the current post.
$_post_id = $attributes['postId'] ?? get_the_ID();
// Don't leak reaction metadata for posts that are not currently publicly queryable.
if ( ! is_post_publicly_queryable( $_post_id ) ) {
return;
}
// Generate a unique ID for the block.
$block_id = 'activitypub-reactions-block-' . wp_unique_id();
/*
* Determine display style - compact style hides avatars.
* For auto-hooked blocks without explicit style, use avatar setting to determine style.
*/
$has_style_class = isset( $attributes['className'] ) && strpos( $attributes['className'], 'is-style-' ) !== false;
if ( ! $has_style_class ) {
$attributes['className'] = trim( ( $attributes['className'] ?? '' ) . ' is-style-' . $default_display_style );
$attributes['displayStyle'] = $default_display_style;
}
$show_avatars = 'facepile' === $attributes['displayStyle'];
// Fetch reactions.
$reactions = array();
foreach ( Comment::get_comment_types() as $_type => $type_object ) {
$_comments = get_comments(
array(
'post_id' => $_post_id,
'type' => $_type,
'status' => 'approve',
'parent' => 0,
)
);
if ( empty( $_comments ) ) {
continue;
}
$count = count( $_comments );
// phpcs:disable WordPress.WP.I18n
$label = sprintf(
_n(
$type_object['count_single'],
$type_object['count_plural'],
$count,
'activitypub'
),
number_format_i18n( $count )
);
// phpcs:enable WordPress.WP.I18n
$reactions[ $_type ] = array(
'label' => $label,
'count' => $count,
'items' => array_map(
static function ( $comment ) {
return array(
'name' => html_entity_decode( $comment->comment_author ),
'url' => $comment->comment_author_url,
'avatar' => get_avatar_url( $comment ),
);
},
$_comments
),
);
}
if ( empty( $reactions ) && ! $attributes['showActions'] ) {
echo '<!-- Reactions block: No reactions found. -->';
return;
}
// Set up the Interactivity API config.
$config = array(
'defaultAvatarUrl' => ACTIVITYPUB_PLUGIN_URL . 'assets/img/mp.jpg',
'namespace' => ACTIVITYPUB_REST_NAMESPACE,
);
if ( $attributes['showActions'] ) {
$config['i18n'] = array(
'copied' => __( 'Copied!', 'activitypub' ),
'copy' => __( 'Copy', 'activitypub' ),
'emptyProfileError' => __( 'Please enter a profile URL or handle.', 'activitypub' ),
'genericError' => __( 'An error occurred. Please try again.', 'activitypub' ),
'intentLabelLike' => __( 'Like this post', 'activitypub' ),
'intentLabelAnnounce' => __( 'Boost this post', 'activitypub' ),
'invalidProfileError' => __( 'Please enter a valid profile URL or handle.', 'activitypub' ),
);
}
wp_interactivity_config( 'activitypub/reactions', $config );
// Set up the Interactivity API state.
wp_interactivity_state( 'activitypub/reactions', array( 'reactions' => array( $_post_id => $reactions ) ) );
// Render a subset of the most recent reactions for facepile.
$reactions = array_map(
static function ( $reaction ) use ( $attributes ) {
$count = 20;
if ( 'wide' === $attributes['align'] ) {
$count = 40;
} elseif ( 'full' === $attributes['align'] ) {
$count = 60;
}
$reaction['items'] = array_slice( array_reverse( $reaction['items'] ), 0, $count );
return $reaction;
},
$reactions
);
// Initialize the context for the block.
$context = array(
'blockId' => $block_id,
'modal' => array(
'isCompact' => true,
'isOpen' => false,
'items' => array(),
'title' => '',
),
'postId' => $_post_id,
'reactions' => $reactions,
);
if ( $attributes['showActions'] ) {
$context['modal']['intent'] = '';
$context['copyButtonText'] = __( 'Copy', 'activitypub' );
$context['errorMessage'] = '';
$context['isError'] = false;
$context['isLoading'] = false;
$context['postUrl'] = get_post_id( $_post_id );
$context['remoteProfile'] = '';
$context['shouldSaveProfile'] = true;
}
// Map comment types to remote intent types.
$intent_map = array(
'like' => 'like',
'repost' => 'announce',
'quote' => 'announce',
);
// Build reactions content.
ob_start();
?>
<div class="activitypub-reactions">
<?php
// First pass: render reaction types that have items (full treatment).
foreach ( $reactions as $_type => $reaction ) :
/* translators: %s: reaction type. */
$aria_label = sprintf( __( 'View all %s', 'activitypub' ), Comment::get_comment_type_attr( $_type, 'label' ) );
$intent = isset( $intent_map[ $_type ] ) ? $intent_map[ $_type ] : '';
?>
<div class="reaction-group" data-reaction-type="<?php echo esc_attr( $_type ); ?>">
<?php if ( $attributes['showActions'] && $intent ) : ?>
<button
class="reaction-action-button has-text-color has-background"
data-intent="<?php echo esc_attr( $intent ); ?>"
data-wp-on--click="actions.openIntentModal"
type="button"
aria-label="<?php echo esc_attr( Comment::get_comment_type_attr( $_type, 'singular' ) ); ?>"
>
<?php echo esc_html( Comment::get_comment_type_attr( $_type, 'singular' ) ); ?>
</button>
<?php endif; ?>
<?php if ( $show_avatars ) : ?>
<ul class="reaction-avatars">
<template data-wp-each="context.reactions.<?php echo esc_attr( $_type ); ?>.items">
<li>
<a
data-wp-bind--href="context.item.url"
data-wp-bind--title="context.item.name"
target="_blank"
rel="noopener noreferrer"
>
<img
data-wp-bind--src="context.item.avatar"
data-wp-bind--alt="context.item.name"
data-wp-on--error="callbacks.setDefaultAvatar"
class="reaction-avatar"
height="32"
width="32"
src=""
alt=""
/>
</a>
</li>
</template>
</ul>
<?php endif; ?>
<button
class="reaction-label has-text-color has-background"
data-reaction-type="<?php echo esc_attr( $_type ); ?>"
data-wp-on--click="actions.toggleModal"
type="button"
aria-label="<?php echo esc_attr( $aria_label ); ?>"
>
<?php echo esc_html( $reaction['label'] ); ?>
</button>
</div>
<?php endforeach; ?>
<?php
// Second pass: render action buttons for reaction types without items.
if ( $attributes['showActions'] ) :
$empty_types = array_diff_key( $intent_map, $reactions );
if ( ! empty( $empty_types ) ) :
?>
<div class="reaction-actions-only" role="group" aria-label="<?php esc_attr_e( 'Reaction actions', 'activitypub' ); ?>">
<?php foreach ( $empty_types as $_type => $intent ) : ?>
<button
class="reaction-action-button has-text-color has-background"
data-intent="<?php echo esc_attr( $intent ); ?>"
data-wp-on--click="actions.openIntentModal"
type="button"
aria-label="<?php echo esc_attr( Comment::get_comment_type_attr( $_type, 'singular' ) ); ?>"
>
<?php echo esc_html( Comment::get_comment_type_attr( $_type, 'singular' ) ); ?>
</button>
<?php endforeach; ?>
</div>
<?php
endif;
endif;
?>
</div>
<?php
$reactions_content = ob_get_clean();
// Build modal content: reactors list (compact) + intent dialog (full-size).
ob_start();
?>
<div data-wp-bind--hidden="!context.modal.isCompact">
<ul class="reactions-list">
<template data-wp-each="context.modal.items">
<li class="reaction-item">
<a data-wp-bind--href="context.item.url" target="_blank" rel="noopener noreferrer">
<?php if ( $show_avatars ) : ?>
<img
alt=""
data-wp-bind--alt="context.item.name"
data-wp-bind--src="context.item.avatar"
data-wp-on--error="callbacks.setDefaultAvatar"
src=""
/>
<?php endif; ?>
<span class="reaction-name" data-wp-text="context.item.name"></span>
</a>
</li>
</template>
</ul>
</div>
<?php if ( $attributes['showActions'] ) : ?>
<div class="activitypub-intent-dialog" data-wp-bind--hidden="context.modal.isCompact">
<div class="activitypub-dialog__section">
<h4><?php esc_html_e( 'Post URL', 'activitypub' ); ?></h4>
<div class="activitypub-dialog__description">
<?php esc_html_e( 'Paste the post URL into the search field of your favorite open social app or platform.', 'activitypub' ); ?>
</div>
<div class="activitypub-dialog__button-group">
<label for="<?php echo esc_attr( $block_id . '-post-url' ); ?>" class="screen-reader-text">
<?php esc_html_e( 'Post URL', 'activitypub' ); ?>
</label>
<input
aria-readonly="true"
class="wp-block-search__input"
id="<?php echo esc_attr( $block_id . '-post-url' ); ?>"
readonly
tabindex="-1"
type="text"
data-wp-bind--value="context.postUrl"
/>
<button
aria-label="<?php esc_attr_e( 'Copy URL to clipboard', 'activitypub' ); ?>"
class="wp-element-button"
data-wp-on--click="actions.copyPostUrl"
type="button"
>
<span data-wp-text="context.copyButtonText"></span>
</button>
</div>
</div>
<div class="activitypub-dialog__section">
<h4><?php esc_html_e( 'Your Profile', 'activitypub' ); ?></h4>
<div class="activitypub-dialog__description">
<?php esc_html_e( 'Or, if you know your own profile, we can start things that way!', 'activitypub' ); ?>
<?php Blocks::render_modal_help(); ?>
</div>
<div class="activitypub-dialog__button-group">
<label for="<?php echo esc_attr( $block_id . '-remote-profile' ); ?>" class="screen-reader-text">
<?php esc_html_e( 'Your Fediverse profile', 'activitypub' ); ?>
</label>
<input
class="wp-block-search__input"
data-wp-bind--aria-invalid="context.isError"
data-wp-bind--value="context.remoteProfile"
data-wp-on--input="actions.updateIntentProfile"
data-wp-on--keydown="actions.onIntentKeydown"
id="<?php echo esc_attr( $block_id . '-remote-profile' ); ?>"
placeholder="<?php esc_attr_e( '@username@example.com', 'activitypub' ); ?>"
type="text"
/>
<button
class="wp-element-button"
data-wp-bind--disabled="context.isLoading"
data-wp-on--click="actions.submitIntent"
type="button"
>
<span data-wp-bind--hidden="context.isLoading"><?php esc_html_e( 'Go', 'activitypub' ); ?></span>
<span data-wp-bind--hidden="!context.isLoading"><?php esc_html_e( 'Loading…', 'activitypub' ); ?></span>
</button>
</div>
<div
class="activitypub-dialog__error"
data-wp-bind--hidden="!context.isError"
data-wp-text="context.errorMessage"
></div>
<div class="activitypub-dialog__remember">
<label>
<input
checked
data-wp-bind--checked="context.shouldSaveProfile"
data-wp-on--change="actions.toggleRememberProfile"
type="checkbox"
/>
<?php esc_html_e( 'Remember my profile for future interactions.', 'activitypub' ); ?>
</label>
</div>
</div>
</div>
<?php endif; ?>
<?php
$modal_content = ob_get_clean();
// Render the shared modal with both contents.
$modal_args = array(
'content' => $modal_content,
);
if ( $attributes['showActions'] ) {
$modal_args['title_binding'] = 'context.modal.title';
} else {
$modal_args['is_compact'] = true;
}
ob_start();
Blocks::render_modal( $modal_args );
$inner_content = $reactions_content . ob_get_clean();
$wrapper_attrs = array(
'id' => $block_id,
'class' => $attributes['className'] ?? '',
'data-wp-interactive' => 'activitypub/reactions',
'data-wp-context' => wp_json_encode( $context, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP ),
'data-wp-init' => 'callbacks.initReactions',
);
$wrapper_attributes = get_block_wrapper_attributes( $wrapper_attrs );
// Render the block with common wrapper.
?>
<div <?php echo $wrapper_attributes; // phpcs:ignore WordPress.Security.EscapeOutput ?>>
<?php echo $content; // phpcs:ignore WordPress.Security.EscapeOutput ?>
<?php echo $inner_content; // phpcs:ignore WordPress.Security.EscapeOutput ?>
</div>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
<?php return array('dependencies' => array('react', 'wp-api-fetch', 'wp-components', 'wp-dom-ready', 'wp-element', 'wp-i18n'), 'version' => 'd5cb95d9bd6062974b3c');
<?php return array('dependencies' => array('@wordpress/interactivity'), 'version' => 'c92a83cbb3c92ac4f478', 'type' => 'module');

View File

@ -0,0 +1 @@
.wp-block-activitypub-reactions .activitypub-modal__overlay.compact .activitypub-modal__frame{max-width:100%;min-width:250px}

File diff suppressed because one or more lines are too long