diff --git a/build/panels.asset.php b/build/panels.asset.php index 9a5e4188b..d596382d9 100644 --- a/build/panels.asset.php +++ b/build/panels.asset.php @@ -1 +1 @@ - array('moment', 'react-jsx-runtime', 'wp-components', 'wp-compose', 'wp-data', 'wp-date', 'wp-dom-ready', 'wp-editor', 'wp-element', 'wp-i18n', 'wp-plugins'), 'version' => 'd92b459db2bb69605022'); + array('moment', 'react-jsx-runtime', 'wp-components', 'wp-compose', 'wp-data', 'wp-date', 'wp-dom-ready', 'wp-editor', 'wp-element', 'wp-i18n', 'wp-plugins'), 'version' => '5cfc4e82d4b3e03141f6'); diff --git a/build/panels.js b/build/panels.js index 960600f09..c6cf67c5b 100644 --- a/build/panels.js +++ b/build/panels.js @@ -1,2 +1,2 @@ -(()=>{"use strict";var e={n:t=>{var s=t&&t.__esModule?()=>t.default:()=>t;return e.d(s,{a:s}),s},d:(t,s)=>{for(var r in s)e.o(s,r)&&!e.o(t,r)&&Object.defineProperty(t,r,{enumerable:!0,get:s[r]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)};const t=window.wp.i18n,s=window.wp.domReady;var r=e.n(s);const n=window.wp.data,a=window.wp.components,i=window.wp.plugins,o=window.wp.editor,l=window.moment;var c=e.n(l);const d=window.wp.element;function u(){(0,n.dispatch)("core/editor")?.editPost({meta:{_non_existing_meta:!0}})}function m(e){if("object"==typeof GatherPress)return e.split(".").reduce(((e,t)=>e&&e[t]),GatherPress)}function p(e,t){if("object"!=typeof GatherPress)return;const s=e.split("."),r=s.pop();s.reduce(((e,t)=>{var s;return null!==(s=e[t])&&void 0!==s?s:e[t]={}}),GatherPress)[r]=t}const g=window.wp.date,h=window.ReactJSXRuntime,_="YYYY-MM-DD HH:mm:ss",v=c().tz(b()).add(1,"day").set("hour",18).set("minute",0).set("second",0).format(_),x=(c().tz(v,b()).add(2,"hours").format(_),[{label:(0,t.__)("1 hour","gatherpress"),value:1},{label:(0,t.__)("1.5 hours","gatherpress"),value:1.5},{label:(0,t.__)("2 hours","gatherpress"),value:2},{label:(0,t.__)("3 hours","gatherpress"),value:3},{label:(0,t.__)("Set an end time…","gatherpress"),value:!1}]);function f(e){return c().tz(function(){let e=m("eventDetails.dateTime.datetime_start");return e=""!==e?c().tz(e,b()).format(_):v,p("eventDetails.dateTime.datetime_start",e),e}(),b()).add(e,"hours").format(_)}function j(){return w(m("settings.dateFormat"))+" "+w(m("settings.timeFormat"))}function b(e=m("eventDetails.dateTime.timezone")){return c().tz.zone(e)?e:(0,t.__)("GMT","gatherpress")}function S(e=""){const t=/^([+-])(\d{2}):(00|15|30|45)$/,s=e.replace(t,"$1");return s!==e?"UTC"+s+parseInt(e.replace(t,"$2")).toString()+e.replace(t,"$3").replace("00","").replace("15",".25").replace("30",".5").replace("45",".75"):e}function D(e,t=null,s=null){!function(e,t=null){const s=c().tz(m("eventDetails.dateTime.datetime_end"),b()).valueOf(),r=c().tz(e,b()).valueOf();r>=s&&P(c().tz(r,b()).add(2,"hours").format(_),t)}(e,s),p("eventDetails.dateTime.datetime_start",e),"function"==typeof t&&t(e),u()}function P(e,t=null,s=null){!function(e,t=null){const s=c().tz(m("eventDetails.dateTime.datetime_start"),b()).valueOf(),r=c().tz(e,b()).valueOf();r<=s&&D(c().tz(r,b()).subtract(2,"hours").format(_),t)}(e,s),p("eventDetails.dateTime.datetime_end",e),null!==t&&t(e),u()}function w(e){const t={d:"DD",D:"ddd",j:"D",l:"dddd",N:"E",S:"o",w:"e",z:"DDD",W:"W",F:"MMMM",m:"MM",M:"MMM",n:"M",t:"",L:"",o:"YYYY",Y:"YYYY",y:"YY",a:"a",A:"A",B:"",g:"h",G:"H",h:"hh",H:"HH",i:"mm",s:"ss",u:"SSS",e:"zz",I:"",O:"",P:"",T:"",Z:"",c:"",r:"",U:"X"};return String(e).split("").map(((e,s,r)=>{const n=r[s-1];return e in t&&"\\"!==n?t[e]:e})).join("")}function T(){const e=c().tz(m("eventDetails.dateTime.datetime_end"),b());return"gatherpress_event"===(0,n.select)("core/editor")?.getCurrentPostType()&&c().tz(b()).valueOf()>e.valueOf()}function C(){const e="gatherpress_event_past",s=(0,n.dispatch)("core/notices");s.removeNotice(e),T()&&s.createNotice("warning",(0,t.__)("This event has already passed.","gatherpress"),{id:e,isDismissible:!1})}const E=()=>{const{editPost:e,unlockPostSaving:s}=(0,n.useDispatch)("core/editor"),r=(0,n.useSelect)((e=>e("core/editor").isCleanNewPost()),[]);let i=(0,n.useSelect)((e=>e("core/editor").getEditedPostAttribute("meta").gatherpress_enable_anonymous_rsvp),[]);r&&(i=m("settings.enableAnonymousRsvp"));const[o,l]=(0,d.useState)(i),c=(0,d.useCallback)((t=>{const r={gatherpress_enable_anonymous_rsvp:Number(t)};l(t),e({meta:r}),s()}),[e,s]);return(0,d.useEffect)((()=>{r&&0!==i&&c(i)}),[r,i,c]),(0,h.jsx)(a.CheckboxControl,{label:(0,t.__)("Enable Anonymous RSVP","gatherpress"),checked:o,onChange:e=>{c(e)}})},y=()=>(0,h.jsx)("section",{children:(0,h.jsx)(E,{})}),k=()=>{const{editPost:e,unlockPostSaving:s}=(0,n.useDispatch)("core/editor"),r=(0,n.useSelect)((e=>e("core/editor").isCleanNewPost()),[]);let i=(0,n.useSelect)((e=>e("core/editor").getEditedPostAttribute("meta").gatherpress_enable_initial_decline),[]);r&&(i=m("settings.enableInitialDecline"));const[o,l]=(0,d.useState)(i),c=(0,d.useCallback)((t=>{const r={gatherpress_enable_initial_decline:Number(t)};l(t),e({meta:r}),s()}),[e,s]);return(0,d.useEffect)((()=>{r&&0!==i&&c(i)}),[r,i,c]),(0,h.jsx)(a.CheckboxControl,{label:(0,t.__)('Enable Immediate "Not Attending" Option for Attendees',"gatherpress"),checked:o,onChange:e=>{c(e)}})},z=()=>(0,h.jsx)("section",{children:(0,h.jsx)(k,{})}),N=()=>{const{dateTimeStart:e,duration:s}=(0,n.useSelect)((e=>({dateTimeStart:e("gatherpress/datetime").getDateTimeStart(),duration:e("gatherpress/datetime").getDuration()})),[]),{setDateTimeStart:r,setDateTimeEnd:i}=(0,n.useDispatch)("gatherpress/datetime"),o=(0,g.getSettings)(),l=/a(?!\\)/i.test(o.formats.time.toLowerCase().replace(/\\\\/g,"").split("").reverse().join(""));return(0,d.useEffect)((()=>{r(c().tz(e,b()).format(_)),s&&i(f(s)),C()}),[e,s,r,i]),(0,h.jsx)(a.PanelRow,{children:(0,h.jsxs)(a.Flex,{direction:"column",gap:"1",children:[(0,h.jsx)(a.FlexItem,{children:(0,h.jsx)("h3",{style:{marginBottom:0},children:(0,h.jsx)("label",{htmlFor:"gatherpress-datetime-start",children:(0,t.__)("Date & time start","gatherpress")})})}),(0,h.jsx)(a.FlexItem,{children:(0,h.jsx)(a.Dropdown,{popoverProps:{placement:"bottom-end"},renderToggle:({isOpen:t,onToggle:s})=>(0,h.jsx)(a.Button,{id:"gatherpress-datetime-start",onClick:s,"aria-expanded":t,isLink:!0,children:c().tz(e,b()).format(j())}),renderContent:()=>(0,h.jsx)(a.DateTimePicker,{currentDate:e,onChange:e=>{D(e,r,i)},is12Hour:l})})})]})})},O=()=>{const{dateTimeEnd:e}=(0,n.useSelect)((e=>({dateTimeEnd:e("gatherpress/datetime").getDateTimeEnd()})),[]),{setDateTimeEnd:s,setDateTimeStart:r}=(0,n.useDispatch)("gatherpress/datetime"),i=(0,g.getSettings)(),o=/a(?!\\)/i.test(i.formats.time.toLowerCase().replace(/\\\\/g,"").split("").reverse().join(""));return(0,d.useEffect)((()=>{s(c().tz(e,b()).format(_)),C()})),(0,h.jsx)(a.PanelRow,{children:(0,h.jsxs)(a.Flex,{direction:"column",gap:"1",children:[(0,h.jsx)(a.FlexItem,{children:(0,h.jsx)("h3",{style:{marginBottom:0},children:(0,h.jsx)("label",{htmlFor:"gatherpress-datetime-end",children:(0,t.__)("Date & time end","gatherpress")})})}),(0,h.jsx)(a.FlexItem,{children:(0,h.jsx)(a.Dropdown,{popoverProps:{placement:"bottom-end"},renderToggle:({isOpen:t,onToggle:s})=>(0,h.jsx)(a.Button,{id:"gatherpress-datetime-end",onClick:s,"aria-expanded":t,isLink:!0,children:c().tz(e,b()).format(j())}),renderContent:()=>(0,h.jsx)(a.DateTimePicker,{currentDate:e,onChange:e=>P(e,s,r),is12Hour:o})})})]})})},A=()=>{const{timezone:e}=(0,n.useSelect)((e=>({timezone:e("gatherpress/datetime").getTimezone()})),[]),{setTimezone:s}=(0,n.useDispatch)("gatherpress/datetime"),r=m("misc.timezoneChoices");return(0,d.useEffect)((()=>{s(m("eventDetails.dateTime.timezone"))}),[s]),(0,h.jsx)(a.PanelRow,{children:(0,h.jsx)(a.SelectControl,{label:(0,t.__)("Time Zone","gatherpress"),value:S(e),onChange:e=>{e=function(e=""){const t=/^UTC([+-])(\d+)(.\d+)?$/,s=e.replace(t,"$1");if(s!==e){const r=e.replace(t,"$2").padStart(2,"0");let n=e.replace(t,"$3");return""===n&&(n=":00"),n=n.replace(".25",":15").replace(".5",":30").replace(".75",":45"),s+r+n}return e}(e),s(e),u()},__nexthasnomarginbottom:!0,children:Object.keys(r).map((e=>(0,h.jsx)("optgroup",{label:e,children:Object.keys(r[e]).map((t=>(0,h.jsx)("option",{value:t,children:r[e][t]},t)))},e)))})})},F=()=>{const{duration:e}=(0,n.useSelect)((e=>({duration:e("gatherpress/datetime").getDuration()})),[]),s=(0,n.useDispatch)(),{setDateTimeEnd:r,setDuration:i}=s("gatherpress/datetime");return(0,h.jsx)(a.SelectControl,{label:(0,t.__)("Duration","gatherpress"),value:!!x.some((t=>t.value===e))&&e,options:x,onChange:e=>{(e="false"!==e&&parseFloat(e))&&r(f(e)),i(e)},__nexthasnomarginbottom:!0})},M=()=>{const e=(0,n.useDispatch)("core/editor").editPost;let t=(0,n.useSelect)((e=>e("core/editor").getEditedPostAttribute("meta")?.gatherpress_datetime));try{t=t?JSON.parse(t):{}}catch(e){t={}}const{dateTimeStart:s,dateTimeEnd:r,duration:a,timezone:i}=(0,n.useSelect)((e=>({dateTimeStart:e("gatherpress/datetime").getDateTimeStart(),dateTimeEnd:e("gatherpress/datetime").getDateTimeEnd(),duration:e("gatherpress/datetime").getDuration(),timezone:e("gatherpress/datetime").getTimezone()})),[]),{setDuration:o}=(0,n.useDispatch)("gatherpress/datetime");return(0,d.useEffect)((()=>{const n=JSON.stringify({...t,dateTimeStart:c().tz(s,i).format(_),dateTimeEnd:c().tz(r,i).format(_),timezone:i});e({meta:{gatherpress_datetime:n}})}),[s,r,i,t,e,o,a]),(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)("section",{children:(0,h.jsx)(N,{})}),(0,h.jsx)("section",{children:a?(0,h.jsx)(F,{}):(0,h.jsx)(O,{})}),(0,h.jsx)("section",{children:(0,h.jsx)(A,{})})]})},Y=()=>(0,h.jsx)(M,{}),L=()=>{const{editPost:e,unlockPostSaving:s}=(0,n.useDispatch)("core/editor"),r=(0,n.useSelect)((e=>e("core/editor").isCleanNewPost()),[]);let i=(0,n.useSelect)((e=>e("core/editor").getEditedPostAttribute("meta").gatherpress_max_guest_limit),[]);r&&(i=m("settings.maxGuestLimit")),!1===i&&(i=0);const[o,l]=(0,d.useState)(i),c=(0,d.useCallback)((t=>{const r={gatherpress_max_guest_limit:Number(t)};l(t),e({meta:r}),s()}),[e,s]);return(0,d.useEffect)((()=>{r&&0!==i&&c(i)}),[r,i,c]),(0,h.jsx)(a.__experimentalNumberControl,{label:(0,t.__)("Maximum Number of Guests","gatherpress"),value:o,min:0,max:5,onChange:e=>{c(e)}})},R=()=>(0,h.jsx)("section",{children:(0,h.jsx)(L,{})}),I=()=>{const{editPost:e,unlockPostSaving:s}=(0,n.useDispatch)("core/editor"),r=(0,n.useSelect)((e=>e("core/editor").isCleanNewPost()),[]);let i=(0,n.useSelect)((e=>e("core/editor").getEditedPostAttribute("meta").gatherpress_max_attendance_limit),[]);r&&(i=m("settings.maxAttendanceLimit")),!1===i&&(i=0);const[o,l]=(0,d.useState)(i),c=(0,d.useCallback)((t=>{const r={gatherpress_max_attendance_limit:Number(t)};l(t),e({meta:r}),s()}),[e,s]);return(0,d.useEffect)((()=>{r&&0!==i&&c(i)}),[r,i,c]),(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(a.__experimentalNumberControl,{label:(0,t.__)("Maximum Attendance Limit","gatherpress"),value:o,min:0,onChange:e=>{c(e)}}),(0,h.jsx)("p",{className:"description",children:(0,t.__)("A value of 0 indicates no limit.","gatherpress")})]})},$=()=>(0,h.jsx)("section",{children:(0,h.jsx)(I,{})}),G=(e,t="")=>{for(const[s,r]of Object.entries(e)){let e=s;t&&(e+="_"+String(t));const n=new CustomEvent(e,{detail:r});dispatchEvent(n)}},H=(e,t="")=>{for(const[s,r]of Object.entries(e)){let e=s;t&&(e+="_"+String(t)),addEventListener(e,(e=>{r(e.detail)}),!1)}},B=()=>"publish"===(0,n.select)("core/editor").getEditedPostAttribute("status")&&!T()&&(0,h.jsxs)("section",{children:[(0,h.jsx)("h3",{style:{marginBottom:"0.5rem"},children:(0,t.__)("Send an event update","gatherpress")}),(0,h.jsx)(a.Button,{variant:"secondary",onClick:()=>G({setOpen:!0}),children:(0,t.__)("Compose Message","gatherpress")})]}),J=()=>{const{editPost:e,unlockPostSaving:s}=(0,n.useDispatch)("core/editor"),r=(0,n.useSelect)((e=>e("core/editor").getEditedPostAttribute("meta").gatherpress_online_event_link)),[i,o]=(0,d.useState)(r);return H({setOnlineEventLink:o},m("eventDetails.postId")),(0,h.jsx)(a.TextControl,{label:(0,t.__)("Online event link","gatherpress"),value:i,placeholder:(0,t.__)("Add link to online event","gatherpress"),onChange:t=>{(t=>{e({meta:{gatherpress_online_event_link:t}}),o(t),G({setOnlineEventLink:t},m("eventDetails.postId")),s()})(t)}})},W=()=>(0,h.jsx)("section",{children:(0,h.jsx)(J,{})}),V=()=>{const[e,s]=(0,d.useState)(""),[r,i]=(0,d.useState)(""),[o,l]=(0,d.useState)(""),[c,u]=(0,d.useState)(""),[m,p]=(0,d.useState)(!1),[g,_]=(0,d.useState)(""),[v,x]=(0,d.useState)(""),[f,j]=(0,d.useState)(""),b=(0,n.useDispatch)("core/editor").editPost,{unlockPostSaving:S}=(0,n.useDispatch)("core/editor"),D=(0,n.useSelect)((e=>e("core/editor").getEditedPostAttribute("_gatherpress_venue"))),P=(0,n.useSelect)((e=>e("core").getEntityRecord("taxonomy","_gatherpress_venue",D))),w=P?.slug.replace(/^_/,""),[T,C]=(0,d.useState)(""),E=D+":"+T,y=(0,n.useSelect)((e=>e("core").getEntityRecords("postType","gatherpress_venue",{per_page:1,slug:T})));(0,d.useEffect)((()=>{var e,r,n,a,o,c;let d={};if(T&&Array.isArray(y)){var m;const e=null!==(m=y[0]?.meta?.gatherpress_venue_information)&&void 0!==m?m:"{}";var p;e&&(d=JSON.parse(e),d.name=null!==(p=y[0]?.title.rendered)&&void 0!==p?p:"")}const g=null!==(e=d?.name)&&void 0!==e?e:(0,t.__)("No venue selected.","gatherpress"),h=null!==(r=d?.fullAddress)&&void 0!==r?r:"",v=null!==(n=d?.phoneNumber)&&void 0!==n?n:"",f=null!==(a=d?.website)&&void 0!==a?a:"",b=null!==(o=d?.latitude)&&void 0!==o?o:"0",S=null!==(c=d?.longitude)&&void 0!==c?c:"0";w&&C(w),j(E?String(E):""),s(g),i(h),l(v),u(f),_(b),x(S),G({setName:g,setFullAddress:h,setPhoneNumber:v,setWebsite:f,setLatitude:b,setLongitude:S,setIsOnlineEventTerm:"online-event"===T})}),[T,y,w,E]);let k=(0,n.useSelect)((e=>e("core").getEntityRecords("taxonomy","_gatherpress_venue",{per_page:-1,context:"view"})),[]);return k?(k=k.map((e=>({label:e.name,value:e.id+":"+e.slug.replace(/^_/,"")}))),k.unshift({value:":",label:(0,t.__)("Choose a venue","gatherpress")})):k=[],(0,h.jsx)(a.PanelRow,{children:(0,h.jsx)(a.SelectControl,{label:(0,t.__)("Venue Selector","gatherpress"),value:f,onChange:e=>{(e=>{j(e);const t=""!==(e=e.split(":"))[0]?[e[0]]:[];b({_gatherpress_venue:t}),C(e[1]),S()})(e)},options:k})})},U=()=>(0,h.jsx)("section",{children:(0,h.jsx)(V,{})});(0,i.registerPlugin)("gatherpress-event-settings",{render:()=>"gatherpress_event"===(0,n.select)("core/editor")?.getCurrentPostType()&&(0,h.jsx)(o.PluginDocumentSettingPanel,{name:"gatherpress-event-settings",title:(0,t.__)("Event settings","gatherpress"),className:"gatherpress-event-settings",children:(0,h.jsxs)(a.__experimentalVStack,{spacing:4,children:[(0,h.jsx)(Y,{}),(0,h.jsx)(U,{}),(0,h.jsx)(W,{}),(0,h.jsx)(R,{}),(0,h.jsx)($,{}),(0,h.jsx)(y,{}),(0,h.jsx)(z,{}),(0,h.jsx)(B,{})]})})}),r()((()=>{const e=(0,n.select)("core/edit-post"),t=(0,n.dispatch)("core/editor");e&&t&&(e.isEditorPanelOpened("gatherpress-event-settings/gatherpress-event-settings")||t.toggleEditorPanelOpened("gatherpress-event-settings/gatherpress-event-settings"))}));const X=window.wp.compose,Z=()=>{var e,s,r;const i=(0,n.useDispatch)("core/editor").editPost,o=e=>{const t=JSON.stringify({...l,...e});i({meta:{gatherpress_venue_information:t}})};let l=(0,n.useSelect)((e=>e("core/editor").getEditedPostAttribute("meta").gatherpress_venue_information));l=l?JSON.parse(l):{};const[c,u]=(0,d.useState)(null!==(e=l.fullAddress)&&void 0!==e?e:""),[m,p]=(0,d.useState)(null!==(s=l.phoneNumber)&&void 0!==s?s:""),[g,_]=(0,d.useState)(null!==(r=l.website)&&void 0!==r?r:"");H({setFullAddress:u,setPhoneNumber:p,setWebsite:_});const v=(0,d.useRef)(o),x=(0,d.useCallback)((()=>{let e=null,s=null;fetch(`https://nominatim.openstreetmap.org/search?q=${c}&format=geojson`).then((e=>{if(!e.ok)throw new Error((0,t.sprintf)(/* translators: %s: Error message */ /* translators: %s: Error message */ -(0,t.__)("Network response was not ok %s","gatherpress"),e.statusText));return e.json()})).then((t=>{t.features.length>0&&(e=t.features[0].geometry.coordinates[1],s=t.features[0].geometry.coordinates[0]),v.current({latitude:e,longitude:s})}))}),[c]),f=(0,X.useDebounce)(x,300);return(0,d.useEffect)((()=>{v.current=o}),[o]),(0,d.useEffect)((()=>{f()}),[c,f]),(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(a.TextControl,{label:(0,t.__)("Full Address","gatherpress"),value:c,onChange:e=>{G({setFullAddress:e}),o({fullAddress:e})}}),(0,h.jsx)(a.TextControl,{label:(0,t.__)("Phone Number","gatherpress"),value:m,onChange:e=>{G({setPhoneNumber:e}),o({phoneNumber:e})}}),(0,h.jsx)(a.TextControl,{label:(0,t.__)("Website","gatherpress"),value:g,type:"url",onChange:e=>{G({setWebsite:e}),o({website:e})}})]})},q=()=>(0,h.jsx)("section",{children:(0,h.jsx)(Z,{})});(0,i.registerPlugin)("gatherpress-venue-settings",{render:()=>"gatherpress_venue"===(0,n.select)("core/editor")?.getCurrentPostType()&&(0,h.jsx)(o.PluginDocumentSettingPanel,{name:"gatherpress-venue-settings",title:(0,t.__)("Venue settings","gatherpress"),className:"gatherpress-venue-settings",children:(0,h.jsx)(a.__experimentalVStack,{spacing:6,children:(0,h.jsx)(q,{})})})}),r()((()=>{const e=(0,n.select)("core/edit-post"),t=(0,n.dispatch)("core/editor");e&&t&&(e.isEditorPanelOpened("gatherpress-venue-settings/gatherpress-venue-settings")||t.toggleEditorPanelOpened("gatherpress-venue-settings/gatherpress-venue-settings"))}))})(); \ No newline at end of file +(()=>{"use strict";var e={n:t=>{var s=t&&t.__esModule?()=>t.default:()=>t;return e.d(s,{a:s}),s},d:(t,s)=>{for(var n in s)e.o(s,n)&&!e.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:s[n]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)};const t=window.wp.i18n,s=window.wp.domReady;var n=e.n(s);const r=window.wp.data,a=window.wp.components,i=window.wp.plugins,o=window.wp.editor,l=window.moment;var c=e.n(l);const d=window.wp.element;function u(){(0,r.dispatch)("core/editor")?.editPost({meta:{_non_existing_meta:!0}})}function m(e){if("object"==typeof GatherPress)return e.split(".").reduce(((e,t)=>e&&e[t]),GatherPress)}function g(e,t){if("object"!=typeof GatherPress)return;const s=e.split("."),n=s.pop();s.reduce(((e,t)=>{var s;return null!==(s=e[t])&&void 0!==s?s:e[t]={}}),GatherPress)[n]=t}const p=window.wp.date,h=window.ReactJSXRuntime,_="YYYY-MM-DD HH:mm:ss",v=c().tz(S()).add(1,"day").set("hour",18).set("minute",0).set("second",0).format(_),x=(c().tz(v,S()).add(2,"hours").format(_),[{label:(0,t.__)("1 hour","gatherpress"),value:1},{label:(0,t.__)("1.5 hours","gatherpress"),value:1.5},{label:(0,t.__)("2 hours","gatherpress"),value:2},{label:(0,t.__)("3 hours","gatherpress"),value:3},{label:(0,t.__)("Set an end time…","gatherpress"),value:!1}]);function j(e){return c().tz(function(){let e=m("eventDetails.dateTime.datetime_start");return e=""!==e?c().tz(e,S()).format(_):v,g("eventDetails.dateTime.datetime_start",e),e}(),S()).add(e,"hours").format(_)}function f(){return w(m("settings.dateFormat"))+" "+w(m("settings.timeFormat"))}function S(e=m("eventDetails.dateTime.timezone")){return c().tz.zone(e)?e:(0,t.__)("GMT","gatherpress")}function b(e=""){const t=/^([+-])(\d{2}):(00|15|30|45)$/,s=e.replace(t,"$1");return s!==e?"UTC"+s+parseInt(e.replace(t,"$2")).toString()+e.replace(t,"$3").replace("00","").replace("15",".25").replace("30",".5").replace("45",".75"):e}function P(e,t=null,s=null){!function(e,t=null){const s=c().tz(m("eventDetails.dateTime.datetime_end"),S()).valueOf(),n=c().tz(e,S()).valueOf();n>=s&&D(c().tz(n,S()).add(2,"hours").format(_),t)}(e,s),g("eventDetails.dateTime.datetime_start",e),"function"==typeof t&&t(e),u()}function D(e,t=null,s=null){!function(e,t=null){const s=c().tz(m("eventDetails.dateTime.datetime_start"),S()).valueOf(),n=c().tz(e,S()).valueOf();n<=s&&P(c().tz(n,S()).subtract(2,"hours").format(_),t)}(e,s),g("eventDetails.dateTime.datetime_end",e),null!==t&&t(e),u()}function w(e){const t={d:"DD",D:"ddd",j:"D",l:"dddd",N:"E",S:"o",w:"e",z:"DDD",W:"W",F:"MMMM",m:"MM",M:"MMM",n:"M",t:"",L:"",o:"YYYY",Y:"YYYY",y:"YY",a:"a",A:"A",B:"",g:"h",G:"H",h:"hh",H:"HH",i:"mm",s:"ss",u:"SSS",e:"zz",I:"",O:"",P:"",T:"",Z:"",c:"",r:"",U:"X"};return String(e).split("").map(((e,s,n)=>{const r=n[s-1];return e in t&&"\\"!==r?t[e]:e})).join("")}function T(){const e=c().tz(m("eventDetails.dateTime.datetime_end"),S());return"gatherpress_event"===(0,r.select)("core/editor")?.getCurrentPostType()&&c().tz(S()).valueOf()>e.valueOf()}function C(){const e="gatherpress_event_past",s=(0,r.dispatch)("core/notices");s.removeNotice(e),T()&&s.createNotice("warning",(0,t.__)("This event has already passed.","gatherpress"),{id:e,isDismissible:!1})}const E=()=>{const{editPost:e,unlockPostSaving:s}=(0,r.useDispatch)("core/editor"),n=(0,r.useSelect)((e=>e("core/editor").isCleanNewPost()),[]);let i=(0,r.useSelect)((e=>e("core/editor").getEditedPostAttribute("meta").gatherpress_enable_anonymous_rsvp),[]);n&&(i=m("settings.enableAnonymousRsvp"));const[o,l]=(0,d.useState)(i),c=(0,d.useCallback)((t=>{const n={gatherpress_enable_anonymous_rsvp:Number(t)};l(t),e({meta:n}),s()}),[e,s]);return(0,d.useEffect)((()=>{n&&0!==i&&c(i)}),[n,i,c]),(0,h.jsx)(a.CheckboxControl,{label:(0,t.__)("Enable Anonymous RSVP","gatherpress"),checked:o,onChange:e=>{c(e)}})},y=()=>(0,h.jsx)("section",{children:(0,h.jsx)(E,{})}),N=()=>{const{editPost:e,unlockPostSaving:s}=(0,r.useDispatch)("core/editor"),n=(0,r.useSelect)((e=>e("core/editor").isCleanNewPost()),[]);let i=(0,r.useSelect)((e=>e("core/editor").getEditedPostAttribute("meta").gatherpress_enable_initial_decline),[]);n&&(i=m("settings.enableInitialDecline"));const[o,l]=(0,d.useState)(i),c=(0,d.useCallback)((t=>{const n={gatherpress_enable_initial_decline:Number(t)};l(t),e({meta:n}),s()}),[e,s]);return(0,d.useEffect)((()=>{n&&0!==i&&c(i)}),[n,i,c]),(0,h.jsx)(a.CheckboxControl,{label:(0,t.__)('Enable Immediate "Not Attending" Option for Attendees',"gatherpress"),checked:o,onChange:e=>{c(e)}})},k=()=>(0,h.jsx)("section",{children:(0,h.jsx)(N,{})}),z=()=>{const{dateTimeStart:e,duration:s}=(0,r.useSelect)((e=>({dateTimeStart:e("gatherpress/datetime").getDateTimeStart(),duration:e("gatherpress/datetime").getDuration()})),[]),{setDateTimeStart:n,setDateTimeEnd:i}=(0,r.useDispatch)("gatherpress/datetime"),o=(0,p.getSettings)(),l=/a(?!\\)/i.test(o.formats.time.toLowerCase().replace(/\\\\/g,"").split("").reverse().join(""));return(0,d.useEffect)((()=>{n(c().tz(e,S()).format(_)),s&&i(j(s)),C()}),[e,s,n,i]),(0,h.jsx)(a.PanelRow,{children:(0,h.jsxs)(a.Flex,{direction:"column",gap:"1",children:[(0,h.jsx)(a.FlexItem,{children:(0,h.jsx)("h3",{style:{marginBottom:0},children:(0,h.jsx)("label",{htmlFor:"gatherpress-datetime-start",children:(0,t.__)("Date & time start","gatherpress")})})}),(0,h.jsx)(a.FlexItem,{children:(0,h.jsx)(a.Dropdown,{popoverProps:{placement:"bottom-end"},renderToggle:({isOpen:t,onToggle:s})=>(0,h.jsx)(a.Button,{id:"gatherpress-datetime-start",onClick:s,"aria-expanded":t,isLink:!0,children:c().tz(e,S()).format(f())}),renderContent:()=>(0,h.jsx)(a.DateTimePicker,{currentDate:e,onChange:e=>{P(e,n,i)},is12Hour:l})})})]})})},O=()=>{const{dateTimeEnd:e}=(0,r.useSelect)((e=>({dateTimeEnd:e("gatherpress/datetime").getDateTimeEnd()})),[]),{setDateTimeEnd:s,setDateTimeStart:n}=(0,r.useDispatch)("gatherpress/datetime"),i=(0,p.getSettings)(),o=/a(?!\\)/i.test(i.formats.time.toLowerCase().replace(/\\\\/g,"").split("").reverse().join(""));return(0,d.useEffect)((()=>{s(c().tz(e,S()).format(_)),C()})),(0,h.jsx)(a.PanelRow,{children:(0,h.jsxs)(a.Flex,{direction:"column",gap:"1",children:[(0,h.jsx)(a.FlexItem,{children:(0,h.jsx)("h3",{style:{marginBottom:0},children:(0,h.jsx)("label",{htmlFor:"gatherpress-datetime-end",children:(0,t.__)("Date & time end","gatherpress")})})}),(0,h.jsx)(a.FlexItem,{children:(0,h.jsx)(a.Dropdown,{popoverProps:{placement:"bottom-end"},renderToggle:({isOpen:t,onToggle:s})=>(0,h.jsx)(a.Button,{id:"gatherpress-datetime-end",onClick:s,"aria-expanded":t,isLink:!0,children:c().tz(e,S()).format(f())}),renderContent:()=>(0,h.jsx)(a.DateTimePicker,{currentDate:e,onChange:e=>D(e,s,n),is12Hour:o})})})]})})},A=()=>{const{timezone:e}=(0,r.useSelect)((e=>({timezone:e("gatherpress/datetime").getTimezone()})),[]),{setTimezone:s}=(0,r.useDispatch)("gatherpress/datetime"),n=m("misc.timezoneChoices");return(0,d.useEffect)((()=>{s(m("eventDetails.dateTime.timezone"))}),[s]),(0,h.jsx)(a.PanelRow,{children:(0,h.jsx)(a.SelectControl,{label:(0,t.__)("Time Zone","gatherpress"),value:b(e),onChange:e=>{e=function(e=""){const t=/^UTC([+-])(\d+)(.\d+)?$/,s=e.replace(t,"$1");if(s!==e){const n=e.replace(t,"$2").padStart(2,"0");let r=e.replace(t,"$3");return""===r&&(r=":00"),r=r.replace(".25",":15").replace(".5",":30").replace(".75",":45"),s+n+r}return e}(e),s(e),u()},__nexthasnomarginbottom:!0,children:Object.keys(n).map((e=>(0,h.jsx)("optgroup",{label:e,children:Object.keys(n[e]).map((t=>(0,h.jsx)("option",{value:t,children:n[e][t]},t)))},e)))})})},F=()=>{const{duration:e}=(0,r.useSelect)((e=>({duration:e("gatherpress/datetime").getDuration()})),[]),s=(0,r.useDispatch)(),{setDateTimeEnd:n,setDuration:i}=s("gatherpress/datetime");return(0,h.jsx)(a.SelectControl,{label:(0,t.__)("Duration","gatherpress"),value:!!x.some((t=>t.value===e))&&e,options:x,onChange:e=>{(e="false"!==e&&parseFloat(e))&&n(j(e)),i(e)},__nexthasnomarginbottom:!0})},M=()=>{const e=(0,r.useDispatch)("core/editor").editPost;let t=(0,r.useSelect)((e=>e("core/editor").getEditedPostAttribute("meta")?.gatherpress_datetime));try{t=t?JSON.parse(t):{}}catch(e){t={}}const{dateTimeStart:s,dateTimeEnd:n,duration:a,timezone:i}=(0,r.useSelect)((e=>({dateTimeStart:e("gatherpress/datetime").getDateTimeStart(),dateTimeEnd:e("gatherpress/datetime").getDateTimeEnd(),duration:e("gatherpress/datetime").getDuration(),timezone:e("gatherpress/datetime").getTimezone()})),[]),{setDuration:o}=(0,r.useDispatch)("gatherpress/datetime");return(0,d.useEffect)((()=>{const r=JSON.stringify({...t,dateTimeStart:c().tz(s,i).format(_),dateTimeEnd:c().tz(n,i).format(_),timezone:i});e({meta:{gatherpress_datetime:r}})}),[s,n,i,t,e,o,a]),(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)("section",{children:(0,h.jsx)(z,{})}),(0,h.jsx)("section",{children:a?(0,h.jsx)(F,{}):(0,h.jsx)(O,{})}),(0,h.jsx)("section",{children:(0,h.jsx)(A,{})})]})},R=()=>(0,h.jsx)(M,{}),Y=()=>{const{editPost:e,unlockPostSaving:s}=(0,r.useDispatch)("core/editor"),n=(0,r.useSelect)((e=>e("core/editor").isCleanNewPost()),[]);let i=(0,r.useSelect)((e=>e("core/editor").getEditedPostAttribute("meta").gatherpress_max_guest_limit),[]);n&&(i=m("settings.maxGuestLimit")),!1===i&&(i=0);const[o,l]=(0,d.useState)(i),c=(0,d.useCallback)((t=>{const n={gatherpress_max_guest_limit:Number(t)};l(t),e({meta:n}),s()}),[e,s]);return(0,d.useEffect)((()=>{n&&0!==i&&c(i)}),[n,i,c]),(0,h.jsx)(a.__experimentalNumberControl,{label:(0,t.__)("Maximum Number of Guests","gatherpress"),value:o,min:0,max:5,onChange:e=>{c(e)}})},L=()=>(0,h.jsx)("section",{children:(0,h.jsx)(Y,{})}),I=()=>{const{editPost:e,unlockPostSaving:s}=(0,r.useDispatch)("core/editor"),n=(0,r.useSelect)((e=>e("core/editor").isCleanNewPost()),[]);let i=(0,r.useSelect)((e=>e("core/editor").getEditedPostAttribute("meta").gatherpress_max_attendance_limit),[]);n&&(i=m("settings.maxAttendanceLimit")),!1===i&&(i=0);const[o,l]=(0,d.useState)(i),c=(0,d.useCallback)((t=>{const n={gatherpress_max_attendance_limit:Number(t)};l(t),e({meta:n}),s()}),[e,s]);return(0,d.useEffect)((()=>{n&&0!==i&&c(i)}),[n,i,c]),(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(a.__experimentalNumberControl,{label:(0,t.__)("Maximum Attendance Limit","gatherpress"),value:o,min:0,onChange:e=>{c(e)}}),(0,h.jsx)("p",{className:"description",children:(0,t.__)("A value of 0 indicates no limit.","gatherpress")})]})},$=()=>(0,h.jsx)("section",{children:(0,h.jsx)(I,{})}),G=(e,t="")=>{for(const[s,n]of Object.entries(e)){let e=s;t&&(e+="_"+String(t));const r=new CustomEvent(e,{detail:n});dispatchEvent(r)}},H=(e,t="")=>{for(const[s,n]of Object.entries(e)){let e=s;t&&(e+="_"+String(t)),addEventListener(e,(e=>{n(e.detail)}),!1)}},B=()=>"publish"===(0,r.select)("core/editor").getEditedPostAttribute("status")&&!T()&&(0,h.jsxs)("section",{children:[(0,h.jsx)("h3",{style:{marginBottom:"0.5rem"},children:(0,t.__)("Send an event update","gatherpress")}),(0,h.jsx)(a.Button,{variant:"secondary",onClick:()=>G({setOpen:!0}),children:(0,t.__)("Compose Message","gatherpress")})]}),J=()=>{const{editPost:e,unlockPostSaving:s}=(0,r.useDispatch)("core/editor"),n=(0,r.useSelect)((e=>e("core/editor").getEditedPostAttribute("meta").gatherpress_online_event_link)),[i,o]=(0,d.useState)(n);return H({setOnlineEventLink:o},m("eventDetails.postId")),(0,h.jsx)(a.TextControl,{label:(0,t.__)("Online event link","gatherpress"),value:i,placeholder:(0,t.__)("Add link to online event","gatherpress"),onChange:t=>{(t=>{e({meta:{gatherpress_online_event_link:t}}),o(t),G({setOnlineEventLink:t},m("eventDetails.postId")),s()})(t)}})},V=()=>(0,h.jsx)("section",{children:(0,h.jsx)(J,{})}),W=()=>{const[e,s]=(0,d.useState)(""),[n,i]=(0,d.useState)(""),[o,l]=(0,d.useState)(""),[c,u]=(0,d.useState)(""),[m,g]=(0,d.useState)(!1),[p,_]=(0,d.useState)(""),[v,x]=(0,d.useState)(""),[j,f]=(0,d.useState)(""),S=(0,r.useDispatch)("core/editor").editPost,{unlockPostSaving:b}=(0,r.useDispatch)("core/editor"),P=(0,r.useSelect)((e=>e("core/editor").getEditedPostAttribute("_gatherpress_venue"))),D=(0,r.useSelect)((e=>e("core").getEntityRecord("taxonomy","_gatherpress_venue",P))),w=D?.slug.replace(/^_/,""),[T,C]=(0,d.useState)(""),E=P+":"+T,y=(0,r.useSelect)((e=>e("core").getEntityRecords("postType","gatherpress_venue",{per_page:1,slug:T})));(0,d.useEffect)((()=>{var e,n,r,a,o,c;let d={};if(T&&Array.isArray(y)){var m;const e=null!==(m=y[0]?.meta?.gatherpress_venue_information)&&void 0!==m?m:"{}";var g;e&&(d=JSON.parse(e),d.name=null!==(g=y[0]?.title.rendered)&&void 0!==g?g:"")}const p=null!==(e=d?.name)&&void 0!==e?e:(0,t.__)("No venue selected.","gatherpress"),h=null!==(n=d?.fullAddress)&&void 0!==n?n:"",v=null!==(r=d?.phoneNumber)&&void 0!==r?r:"",j=null!==(a=d?.website)&&void 0!==a?a:"",S=null!==(o=d?.latitude)&&void 0!==o?o:"0",b=null!==(c=d?.longitude)&&void 0!==c?c:"0";w&&C(w),f(E?String(E):""),s(p),i(h),l(v),u(j),_(S),x(b),G({setName:p,setFullAddress:h,setPhoneNumber:v,setWebsite:j,setLatitude:S,setLongitude:b,setIsOnlineEventTerm:"online-event"===T})}),[T,y,w,E]);let N=(0,r.useSelect)((e=>e("core").getEntityRecords("taxonomy","_gatherpress_venue",{per_page:-1,context:"view"})),[]);return N?(N=N.map((e=>({label:e.name,value:e.id+":"+e.slug.replace(/^_/,"")}))),N.unshift({value:":",label:(0,t.__)("Choose a venue","gatherpress")})):N=[],(0,h.jsx)(a.PanelRow,{children:(0,h.jsx)(a.SelectControl,{label:(0,t.__)("Venue Selector","gatherpress"),value:j,onChange:e=>{(e=>{f(e);const t=""!==(e=e.split(":"))[0]?[e[0]]:[];S({_gatherpress_venue:t}),C(e[1]),b()})(e)},options:N})})},U=()=>(0,h.jsx)("section",{children:(0,h.jsx)(W,{})}),{Fill:X,Slot:Z}=(0,a.createSlotFill)("EventPluginDocumentSettings"),q=({children:e,className:t})=>(0,h.jsx)(X,{children:(0,h.jsx)(a.PanelRow,{className:t,children:e})});q.Slot=Z,(0,i.registerPlugin)("gatherpress-event-settings",{render:()=>"gatherpress_event"===(0,r.select)("core/editor")?.getCurrentPostType()&&(0,h.jsxs)(o.PluginDocumentSettingPanel,{name:"gatherpress-event-settings",title:(0,t.__)("Event settings","gatherpress"),className:"gatherpress-event-settings",children:[(0,h.jsx)(q.Slot,{}),(0,h.jsxs)(a.__experimentalVStack,{spacing:4,children:[(0,h.jsx)(R,{}),(0,h.jsx)(U,{}),(0,h.jsx)(V,{}),(0,h.jsx)(L,{}),(0,h.jsx)($,{}),(0,h.jsx)(y,{}),(0,h.jsx)(k,{}),(0,h.jsx)(B,{})]})]})}),n()((()=>{const e=(0,r.select)("core/edit-post"),t=(0,r.dispatch)("core/editor");e&&t&&(e.isEditorPanelOpened("gatherpress-event-settings/gatherpress-event-settings")||t.toggleEditorPanelOpened("gatherpress-event-settings/gatherpress-event-settings"))}));const K=window.wp.compose,Q=()=>{var e,s,n;const i=(0,r.useDispatch)("core/editor").editPost,o=e=>{const t=JSON.stringify({...l,...e});i({meta:{gatherpress_venue_information:t}})};let l=(0,r.useSelect)((e=>e("core/editor").getEditedPostAttribute("meta").gatherpress_venue_information));l=l?JSON.parse(l):{};const[c,u]=(0,d.useState)(null!==(e=l.fullAddress)&&void 0!==e?e:""),[m,g]=(0,d.useState)(null!==(s=l.phoneNumber)&&void 0!==s?s:""),[p,_]=(0,d.useState)(null!==(n=l.website)&&void 0!==n?n:"");H({setFullAddress:u,setPhoneNumber:g,setWebsite:_});const v=(0,d.useRef)(o),x=(0,d.useCallback)((()=>{let e=null,s=null;fetch(`https://nominatim.openstreetmap.org/search?q=${c}&format=geojson`).then((e=>{if(!e.ok)throw new Error((0,t.sprintf)(/* translators: %s: Error message */ /* translators: %s: Error message */ +(0,t.__)("Network response was not ok %s","gatherpress"),e.statusText));return e.json()})).then((t=>{t.features.length>0&&(e=t.features[0].geometry.coordinates[1],s=t.features[0].geometry.coordinates[0]),v.current({latitude:e,longitude:s})}))}),[c]),j=(0,K.useDebounce)(x,300);return(0,d.useEffect)((()=>{v.current=o}),[o]),(0,d.useEffect)((()=>{j()}),[c,j]),(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(a.TextControl,{label:(0,t.__)("Full Address","gatherpress"),value:c,onChange:e=>{G({setFullAddress:e}),o({fullAddress:e})}}),(0,h.jsx)(a.TextControl,{label:(0,t.__)("Phone Number","gatherpress"),value:m,onChange:e=>{G({setPhoneNumber:e}),o({phoneNumber:e})}}),(0,h.jsx)(a.TextControl,{label:(0,t.__)("Website","gatherpress"),value:p,type:"url",onChange:e=>{G({setWebsite:e}),o({website:e})}})]})},ee=()=>(0,h.jsx)("section",{children:(0,h.jsx)(Q,{})}),{Fill:te,Slot:se}=(0,a.createSlotFill)("VenuePluginDocumentSettings"),ne=({children:e,className:t})=>(0,h.jsx)(te,{children:(0,h.jsx)(a.PanelRow,{className:t,children:e})});ne.Slot=se,(0,i.registerPlugin)("gatherpress-venue-settings",{render:()=>"gatherpress_venue"===(0,r.select)("core/editor")?.getCurrentPostType()&&(0,h.jsxs)(o.PluginDocumentSettingPanel,{name:"gatherpress-venue-settings",title:(0,t.__)("Venue settings","gatherpress"),className:"gatherpress-venue-settings",children:[(0,h.jsx)(ne.Slot,{}),(0,h.jsx)(a.__experimentalVStack,{spacing:6,children:(0,h.jsx)(ee,{})})]})}),(0,i.registerPlugin)("gatherpress-venue-settings-at-events",{render:function(){return(0,h.jsx)(h.Fragment,{children:(0,h.jsx)(a.Fill,{name:"EventPluginDocumentSettings",children:(0,h.jsx)(ne.Slot,{})})})}}),n()((()=>{const e=(0,r.select)("core/edit-post"),t=(0,r.dispatch)("core/editor");e&&t&&(e.isEditorPanelOpened("gatherpress-venue-settings/gatherpress-venue-settings")||t.toggleEditorPanelOpened("gatherpress-venue-settings/gatherpress-venue-settings"))}))})(); \ No newline at end of file diff --git a/docs/developer/blocks/README.md b/docs/developer/blocks/README.md new file mode 100644 index 000000000..f626e2f7d --- /dev/null +++ b/docs/developer/blocks/README.md @@ -0,0 +1,6 @@ +# Blocks in GatherPress + +1. All blocks in general (LINK to /docs/user/...) +2. [Hookable patterns for events & venues](./hookable-patterns/) + - Add to or Remove blocks from the post type block templates +3. [Slots & fills in GatherPress Admin UI](./slot-fills/) diff --git a/docs/developer/blocks/hookable-patterns/README.md b/docs/developer/blocks/hookable-patterns/README.md new file mode 100644 index 000000000..2d8f11b4f --- /dev/null +++ b/docs/developer/blocks/hookable-patterns/README.md @@ -0,0 +1,42 @@ +# Hookable patterns for events & venues + +GatherPress registers multiple invisible block-patterns, that are used as template properties of the main post types. + +Patterns allow to be filtered by the (upgraded since WordPress 6.5) Block Hooks API. Making use of this API brings some advantages, which are at least: + +- GatherPress' blocks can be easily moved, modified or removed by extenders via standardized core code +- GatherPress provides central entry points for plugin developers to hook in own blocks, to extend GatherPress +- GatherPress' blocks will provide their hooking code themself, which keeps concerns separate and code clean + +For example when you create a new event post, it gets pre-poulated with a set of blocks, curated within a block-pattern named `gatherpress/event-template`. + +GatherPress combines four of such block-patterns to curate the creation of: + +- [New Events](#new-event) +- [New Venues](#new-venue) +- [New Event Queries within any post](#new-event-queries-within-any-post) +- [Venue Details within any post](#venue-details-within-any-post) + +## New Event + +GatherPress adds the following blocks by default into a new created event: + +- A block-pattern named `gatherpress/event-template`. + + +## New Venue + +A new created venue will have the following blocks prepared by default: + +- A block-pattern named `gatherpress/venue-template` + - A block-pattern named `gatherpress/venue-details`, which keeps detailed information about a selected venue in the shape of blocks + +## New Event Queries within any post + +## Venue Details within any post + +### Resources + +- [@wordpress/hooks - Block Editor Handbook | Developer.WordPress.org](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-hooks/) +- [#devnote - Introducing Block Hooks for dynamic blocks - Make WordPress Core](https://make.wordpress.org/core/2023/10/15/introducing-block-hooks-for-dynamic-blocks/) +- [Exploring the Block Hooks API in WordPress 6.5 - WordPress Developer Blog](https://developer.wordpress.org/news/2024/03/25/exploring-the-block-hooks-api-in-wordpress-6-5/) diff --git a/docs/developer/blocks/slot-fills/README.md b/docs/developer/blocks/slot-fills/README.md new file mode 100644 index 000000000..5b52e5628 --- /dev/null +++ b/docs/developer/blocks/slot-fills/README.md @@ -0,0 +1,42 @@ +# Slots & fills in GatherPress Admin UI + +Similar to the central entry points for blocks – GatherPress' [hookable-patterns](./../hookable-patterns/), the plugin provides central administrative entry-points within the post- and site-editor for all block settings. + +GatherPress keeps relevant post data about the currently edited venue or event post within slot inside the `InseptorControls` panel, specific for each post type. These open slots are used by GatherPress itself and can be filled externally. + +Every slot belongs to one of each post type. Additionally the venue-slot will be added to the event-slot automatically. + +Every GatherPress block with own administrative sidebar-elements registers a fill for either the venue- or the events-slot. Plugin developers should provide their additions to GatherPress within the slots as well, which will help keeping the overall admin interface clean & consistent. + +## Available Slots + +- `EventPluginDocumentSettings` A slot that has all settings related to an event. +- `VenuePluginDocumentSettings` A slot that has all settings related to a venue. + +All slots will be rendered into the `PluginDocumentSettingPanel` imported from the `@wordpress/editor` package. This panel is shown in the document sidebar for the event and venue post types [in both the post and site editor][devnote]. + +## Fills by GatherPress + +- `VenuePluginFill` loads the `VenuePluginDocumentSettings` slot into the `EventPluginDocumentSettings` slot, so that venue changes can be made from within an event context. + + +## Add or remove UI elements + +```js +export default function GatherPressAwesomeFill() { + return ( + <> + +

A note that will be seen in the document sidebar under "Event settings".

+
+ + ); +} +``` + + +### Resources + +- [Unified Extensibility APIs in 6.6][devnote] + +[devnote]: https://make.wordpress.org/core/2024/06/18/editor-unified-extensibility-apis-in-6-6/ "#devnote - Editor: Unified Extensibility APIs in 6.6 – Make WordPress Core" diff --git a/includes/core/classes/class-block.php b/includes/core/classes/class-block.php index a20b606cf..79789ff71 100644 --- a/includes/core/classes/class-block.php +++ b/includes/core/classes/class-block.php @@ -49,6 +49,7 @@ protected function __construct() { * @return void */ protected function setup_hooks(): void { + add_action( 'init', array( $this, 'register_block_patterns' ) ); // Priority 11 needed for block.json translations of title and description. add_action( 'init', array( $this, 'register_blocks' ), 11 ); } @@ -72,4 +73,64 @@ public function register_blocks(): void { ); } } + + /** + * Register block patterns. + * + * This method registers multiple different block-patterns for GatherPress. + * + * @since 1.0.0 + * @see https://developer.wordpress.org/reference/functions/register_block_pattern/ + * + * @return void + */ + public function register_block_patterns(): void { + $block_patterns = array( + array( + 'gatherpress/event-template', + array( + 'title' => __( 'Invisible Event Template Block Pattern', 'gatherpress' ), + // Even this paragraph seems useless, it's not. + // It is the entry point for all our hooked blocks + // and as such absolutely important! + 'content' => '', // Other blocks are hooked-in here. + 'inserter' => false, + 'source' => 'plugin', + ), + ), + array( + 'gatherpress/venue-template', + array( + 'title' => __( 'Invisible Venue Template Block Pattern', 'gatherpress' ), + // Even this paragraph seems useless, it's not. + // It is the entry point for all our hooked blocks + // and as such absolutely important! + 'content' => '

', // Other blocks are hooked-in here. + 'inserter' => false, + 'source' => 'plugin', + ), + ), + array( + 'gatherpress/venue-details', + array( + 'title' => __( 'Invisible Venue Details Block Pattern', 'gatherpress' ), + // Even this post-title seems useless, it's not. + // It is the entry point for all our hooked blocks + // and as such absolutely important! + 'content' => '', // Other blocks are hooked-in here. + 'inserter' => false, + 'source' => 'plugin', + ), + ), + ); + + foreach ( $block_patterns as $block_pattern ) { + /** + * Made to be used with the 'template' parameter + * when registering the 'gatherpress_event' post type + * and will not be visible to the editor at any point. + */ + register_block_pattern( $block_pattern[0], $block_pattern[1] ); + } + } } diff --git a/includes/core/classes/class-event-setup.php b/includes/core/classes/class-event-setup.php index c2b57e16a..7f0cad2e9 100644 --- a/includes/core/classes/class-event-setup.php +++ b/includes/core/classes/class-event-setup.php @@ -128,6 +128,7 @@ public function register_post_type(): void { ), ), array( 'gatherpress/rsvp-response' ), + // The future! // array( 'core/pattern', array( 'slug' => 'gatherpress/event-template' ) ), // phpcs:ignore Squiz.PHP.CommentedOutCode.Found ! ), 'menu_position' => 4, 'supports' => array( diff --git a/includes/core/classes/class-venue.php b/includes/core/classes/class-venue.php index 367b84f56..057864de4 100644 --- a/includes/core/classes/class-venue.php +++ b/includes/core/classes/class-venue.php @@ -132,6 +132,7 @@ public function register_post_type(): void { 'menu_icon' => 'dashicons-location', 'template' => array( array( 'gatherpress/venue' ), + // The future! // array( 'core/pattern', array( 'slug' => 'gatherpress/venue-template' ) ), // phpcs:ignore Squiz.PHP.CommentedOutCode.Found ! ), 'has_archive' => true, 'rewrite' => array( @@ -232,6 +233,8 @@ public function register_taxonomy(): void { 'show_in_rest' => true, ) ); + // It is necessary to make this taxonomy visible on event posts, within REST responses. + register_taxonomy_for_object_type( self::TAXONOMY, Event::POST_TYPE ); } /** diff --git a/src/panels/event-settings/index.js b/src/panels/event-settings/index.js index 39cef13fc..b52cffb0a 100644 --- a/src/panels/event-settings/index.js +++ b/src/panels/event-settings/index.js @@ -23,6 +23,7 @@ import MaxAttendanceLimitPanel from './max-attendance-limit'; import NotifyMembersPanel from './notify-members'; import OnlineEventLinkPanel from './online-link'; import VenueSelectorPanel from './venue-selector'; +import { EventPluginDocumentSettings } from './slot'; /** * A settings panel for event-specific settings in the block editor. @@ -44,6 +45,9 @@ const EventSettings = () => { title={__('Event settings', 'gatherpress')} className="gatherpress-event-settings" > + {/* Extendable entry point for "Event Settings" panel. */} + + diff --git a/src/panels/event-settings/slot.js b/src/panels/event-settings/slot.js new file mode 100644 index 000000000..0c0285cca --- /dev/null +++ b/src/panels/event-settings/slot.js @@ -0,0 +1,17 @@ +/** + * Defines an extensibility slot for the "Event Settings" panel. + */ + +/** + * WordPress dependencies + */ +import { createSlotFill, PanelRow } from '@wordpress/components'; + +export const { Fill, Slot } = createSlotFill('EventPluginDocumentSettings'); +export const EventPluginDocumentSettings = ({ children, className }) => ( + + {children} + +); + +EventPluginDocumentSettings.Slot = Slot; diff --git a/src/panels/venue-settings/fill.js b/src/panels/venue-settings/fill.js new file mode 100644 index 000000000..eaa3ab457 --- /dev/null +++ b/src/panels/venue-settings/fill.js @@ -0,0 +1,24 @@ +/** + * Fill the "Venue Settings" slot into the "Event Settings" slot by default, + * so that venue changes can be made from within an event context. + */ + +/** + * WordPress dependencies + */ +import { Fill } from '@wordpress/components'; + +/** + * Internal dependencies + */ +import { VenuePluginDocumentSettings } from './slot'; + +export default function VenuePluginFill() { + return ( + <> + + + + + ); +} diff --git a/src/panels/venue-settings/index.js b/src/panels/venue-settings/index.js index bd60c4d56..11baaf89c 100644 --- a/src/panels/venue-settings/index.js +++ b/src/panels/venue-settings/index.js @@ -16,6 +16,8 @@ import { PluginDocumentSettingPanel } from '@wordpress/editor'; */ import { isVenuePostType } from '../../helpers/venue'; import VenueInformationPanel from './venue-information'; +import { VenuePluginDocumentSettings } from './slot'; +import VenuePluginFill from './fill'; /** * VenueSettings Component @@ -35,6 +37,9 @@ const VenueSettings = () => { title={__('Venue settings', 'gatherpress')} className="gatherpress-venue-settings" > + {/* Extendable entry point for "Venue Settings" panel. */} + + @@ -56,6 +61,10 @@ registerPlugin('gatherpress-venue-settings', { render: VenueSettings, }); +registerPlugin('gatherpress-venue-settings-at-events', { + render: VenuePluginFill, +}); + /** * Toggle Venue Settings Panel * diff --git a/src/panels/venue-settings/slot.js b/src/panels/venue-settings/slot.js new file mode 100644 index 000000000..4f92d6efb --- /dev/null +++ b/src/panels/venue-settings/slot.js @@ -0,0 +1,17 @@ +/** + * Defines as extensibility slot for the "Venue Settings" panel. + */ + +/** + * WordPress dependencies + */ +import { createSlotFill, PanelRow } from '@wordpress/components'; + +export const { Fill, Slot } = createSlotFill('VenuePluginDocumentSettings'); +export const VenuePluginDocumentSettings = ({ children, className }) => ( + + {children} + +); + +VenuePluginDocumentSettings.Slot = Slot;