From 1aa7c404dae63c9518468fe9b579fad819f8d871 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Sun, 13 Sep 2026 18:32:43 +0000
Subject: [PATCH] =Single Event page setup done through the new Event block. Currently working on the Simple Calendar block setup
---
inc/integrations/SyncToPost.php | 4
build/meta/index.asset.php | 2
jvb.php | 3
build/_meta/fields.asset.php | 2
build/event/view.js | 0
src/event/block.json | 24 +
src/_meta/fields/upload-field.js | 9
build/event/index.js | 1
src/event/editor.scss | 20 +
src/_meta/fields/datetime-field.js | 4
inc/blocks/EventBlock.php | 300 ++++++++++++++++
src/simple-calendar/style.scss | 9
build/simple-calendar/style-index.css | 2
inc/registrar/helpers/AddCustomFields.php | 9
build/_meta/fields.js | 2
build/event/index.asset.php | 1
build/event/render.php | 5
inc/managers/DirectoryManager.php | 4
build/simple-calendar/style-index-rtl.css | 2
build/simple-calendar/index.asset.php | 2
inc/registrar/Registrar.php | 11
build/event/index.css | 1
src/event/render.php | 5
build/event/block.json | 29 +
inc/meta/Meta.php | 3
inc/registrar/helpers/MakeCalendarType.php | 28 +
inc/blocks/_setup.php | 5
src/event/index.php | 0
src/event/view.js | 1
inc/integrations/services/Cloudflare.php | 22 +
inc/blocks/SimpleCalendarBlock.php | 280 +++++++++++++-
src/_meta/fields/selector-field.js | 4
src/event/edit.js | 29 +
build/event/style-index.css | 1
inc/blocks/FAQBlock.php | 5
inc/integrations/SyncToUser.php | 5
src/event/save.js | 3
inc/meta/Sanitizer.php | 40 +
build/event/view.asset.php | 1
inc/registrar/Fields.php | 62 +-
inc/blocks/MenuBlock.php | 2
src/event/style.scss | 60 +++
build/event/style-index-rtl.css | 1
inc/integrations/SyncToTerm.php | 5
build/event/index-rtl.css | 1
build/meta/index.js | 2
src/event/index.js | 39 ++
inc/integrations/SyncHelpers.php | 2
src/_meta/fields/date-field.js | 3
49 files changed, 941 insertions(+), 114 deletions(-)
diff --git a/build/_meta/fields.asset.php b/build/_meta/fields.asset.php
index 3a0b921..e1d8d15 100644
--- a/build/_meta/fields.asset.php
+++ b/build/_meta/fields.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react', 'react-jsx-runtime', 'wp-api-fetch', 'wp-block-editor', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-editor', 'wp-element', 'wp-i18n', 'wp-media-utils', 'wp-plugins', 'wp-url'), 'version' => 'b289cda300edfd519494');
+<?php return array('dependencies' => array('react', 'react-jsx-runtime', 'wp-api-fetch', 'wp-block-editor', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-editor', 'wp-element', 'wp-i18n', 'wp-media-utils', 'wp-plugins', 'wp-url'), 'version' => '7d164cd5586570c7c4fc');
diff --git a/build/_meta/fields.js b/build/_meta/fields.js
index 372eb41..e36820e 100644
--- a/build/_meta/fields.js
+++ b/build/_meta/fields.js
@@ -1 +1 @@
-(()=>{"use strict";const e={n:l=>{const t=l&&l.__esModule?()=>l.default:()=>l;return e.d(t,{a:t}),t},d:(l,t)=>{for(var n in t)e.o(t,n)&&!e.o(l,n)&&Object.defineProperty(l,n,{enumerable:!0,get:t[n]})},o:(e,l)=>Object.hasOwn(e,l)},l=window.wp.plugins,t=(window.wp.i18n,window.wp.compose),n=window.wp.data,a=window.wp.editor,i=window.wp.coreData,s=window.wp.components,o=window.ReactJSXRuntime,r={text:"text",email:"email",tel:"tel",url:"url",number:"number"},d=({field:e,value:l,onChange:t})=>"textarea"===e.type?(0,o.jsx)(s.TextareaControl,{label:e.label,help:e.description,value:l??"",onChange:t,id:e.name}):(0,o.jsx)(s.TextControl,{label:e.label,help:e.description,type:r[e.type]||"text",value:l??"",onChange:t,required:e.required,id:e.name}),c=({field:e,value:l,onChange:t})=>{const n=Object.entries(e.options||{}).map(([e,l])=>({label:l,value:e}));return"radio"===e.type?(0,o.jsx)(s.RadioControl,{label:e.label,help:e.description,selected:l,options:n,onChange:t,id:e.name}):(0,o.jsx)(s.SelectControl,{label:e.label,help:e.description,value:l??"",options:[{label:"— Select —",value:""},...n],onChange:t,id:e.name})},p=({field:e,value:l,onChange:t})=>{const n=Array.isArray(l)?l:[];return(0,o.jsxs)("fieldset",{id:e.name,children:[(0,o.jsx)("legend",{className:"jvb-field-label",children:e.label}),Object.entries(e.options||{}).map(([e,l])=>(0,o.jsx)(s.CheckboxControl,{label:l,checked:n.includes(e),onChange:l=>((e,l)=>{t(l?[...n,e]:n.filter(l=>l!==e))})(e,l)},e))]})},u=window.React,m=e=>{if(!e)return null;const[l,t,n]=e.split("-").map(Number);return new Date(l,t-1,n)},h=e=>{if(e.description&&0!==e.description.length)return(0,o.jsx)("p",{className:"hint",children:e.description})},v=e=>{if(e.description&&0!==e.description.length)return(0,o.jsx)("p",{className:"hint",children:e.description})},b=window.wp.element,j=(e,l,t)=>e?.includes("{{")?e.replace(/{{(.*?)}}/g,(e,t)=>{const n=l[t];return void 0===n?"":Array.isArray(n)?n.join(", "):String(n)}):e,x=window.wp.mediaUtils,g=window.wp.blockEditor,f=window.wp.apiFetch;var w=e.n(f);const y={image:"image",video:"video",document:"application",all:""},C=({id:e,onRemove:l})=>{const[t,n]=(0,b.useState)(null);(0,b.useEffect)(()=>{let l=!1;if(e)return w()({path:`/wp/v2/media/${e}`}).then(e=>!l&&n(e)).catch(()=>{}),()=>{l=!0}},[e]);const a=t?.media_details?.sizes?.thumbnail?.source_url||t?.source_url,i="image"===t?.media_type;return(0,o.jsxs)("div",{className:"jvb-upload-thumb",children:[i&&a?(0,o.jsx)("img",{src:a,alt:t?.alt_text||""}):(0,o.jsx)("div",{className:"jvb-upload-thumb-placeholder",children:t?.title?.rendered||`#${e}`}),(0,o.jsx)(s.Button,{variant:"link",isDestructive:!0,onClick:()=>l(e),children:"Remove"})]})},_=window.wp.url,k=e=>e.subtype||e.type,S=(e,l,t)=>"post"===l?{title:t,status:"publish",postType:e.post_type}:{name:t},N=(e,l)=>"user"===l?e.name:e.title?.rendered??e.title??e.name,A={text:d,email:d,tel:d,url:d,number:d,textarea:d,select:c,radio:c,checkbox:p,set:p,true_false:({field:e,value:l,onChange:t})=>(0,o.jsx)(s.ToggleControl,{label:e.label,help:e.description,checked:!!l,onChange:t,id:e.name}),date:({field:e,value:l,onChange:t})=>(0,o.jsxs)("div",{className:"components-base-control",id:e.name,children:[(0,o.jsx)("label",{className:"components-base-control__label",children:e.label}),(0,o.jsx)(s.DatePicker,{currentDate:m(l),onChange:t,help:e.description}),h(e)]}),time:({field:e,value:l,onChange:t})=>(0,o.jsx)(s.BaseControl,{label:e.label,help:e.description,id:e.name,children:(0,o.jsx)("input",{type:"time",id:e.name,value:l??"",onChange:e=>t(e.target.value)})}),datetime:({field:e,value:l,onChange:t})=>{const[n,a]=(0,u.useState)(new Date);return(0,o.jsxs)("div",{className:"components-base-control",id:e.name,children:[(0,o.jsx)("label",{className:"components-base-control__label",children:e.label}),(0,o.jsx)(s.DateTimePicker,{currentDate:n,onChange:t,label:e.label,help:e.description,value:l??"",is12Hour:!0}),v(e)]})},repeater:({field:e,value:l,onChange:t,meta:n})=>{const a=Array.isArray(l)?l:[],i=e.fields||{},[r,d]=(0,b.useState)(null);return(0,o.jsxs)("div",{className:"jvb-repeater-field",id:e.name,children:[(0,o.jsx)("p",{className:"jvb-field-label",children:e.label}),(0,o.jsx)(s.Panel,{children:a.map((l,c)=>(0,o.jsxs)(s.PanelBody,{title:j(e.row_label,l)||`Row ${c+1}`,initialOpen:r===c,onToggle:()=>d(r===c?null:c),children:[Object.entries(i).map(([e,i])=>(0,o.jsx)(R,{field:{...i,name:e},value:l[e],onChange:l=>((e,l,n)=>{const i=a.map((t,a)=>a===e?{...t,[l]:n}:t);t(i)})(c,e,l),meta:n},e)),(0,o.jsx)(s.Button,{variant:"link",isDestructive:!0,onClick:()=>(e=>t(a.filter((l,t)=>t!==e)))(c),children:"Remove"})]},c))}),(0,o.jsx)(s.Button,{variant:"secondary",onClick:()=>{return t([...a,(e=i,Object.fromEntries(Object.entries(e||{}).map(([e,l])=>[e,l.default??""])))]);var e},children:e.add_label||"Add Row"})]})},upload:({field:e,value:l,onChange:t})=>{const n=e.multiple||"gallery"===e.type,a=n?Array.isArray(l)?l:[]:l,i=y[e.subtype]?[y[e.subtype]]:"",r=e=>{t(n?a.filter(l=>l!==e):0)};return(0,o.jsxs)("div",{className:"jvb-upload-field",id:e.name,children:[(0,o.jsx)("p",{className:"jvb-field-label",children:e.label}),(0,o.jsx)("div",{className:n?"jvb-upload-grid":"jvb-upload-single",children:n?a.map(e=>(0,o.jsx)(C,{id:e,onRemove:r},e)):!!a&&(0,o.jsx)(C,{id:a,onRemove:r})}),(0,o.jsx)(g.MediaUploadCheck,{children:(0,o.jsx)(x.MediaUpload,{onSelect:e=>t(n?e.map(e=>e.id):e.id),allowedTypes:i,multiple:n,value:n?a:a||void 0,render:({open:l})=>(0,o.jsxs)(s.Button,{variant:"secondary",onClick:l,children:[(n?a.length:a)?"Change":"Select"," ",e.label]})})})]})},selector:({field:e,value:l,onChange:t})=>{const n=k(e),a="taxonomy"===n,i=(e=>{const l=k(e);return"user"===l?e=>(0,_.addQueryArgs)("/wp/v2/users",{search:e,per_page:20}):"taxonomy"===l?l=>(0,_.addQueryArgs)(`/wp/v2/${e.taxonomy}`,{search:l,per_page:20,hide_empty:!1}):l=>(0,_.addQueryArgs)("/wp/v2/search",{search:l,type:"post",subtype:e.post_type,per_page:20})})(e),r=Array.isArray(l)?l:l?l.split(","):[],[d,c]=(0,b.useState)([]),[p,u]=(0,b.useState)({}),[m,h]=(0,b.useState)({}),[v,j]=(0,b.useState)(""),[x,g]=(0,b.useState)(!1),f=v?`Not found. Create "${v}"?`:null;(0,b.useEffect)(()=>{y("");let e=!1;if(r.length)return Promise.all(r.map(e=>w()({path:i("")+`&include=${e}`}))).then(l=>{if(e)return;const t={},a=[];l.flat().forEach(e=>{const l=N(e,n);t[l]=e.id,a.push(l)}),u(e=>({...e,...t})),c(a)}).catch(()=>{}),()=>{e=!0};c([])},[JSON.stringify(r)]);const y=(0,b.useCallback)(e=>{j(e),w()({path:i(e)}).then(e=>{const l={};e.forEach(e=>{l[N(e,n)]=e.id}),h(l)}).catch(()=>{})},[i,n]),C=l=>{const n=1===e.max;t(n?l[l.length-1]??0:(e.max?l.slice(0,e.max):l).join(","))},A=v&&!Object.keys(m).some(e=>e.toLowerCase()===v.toLowerCase()),O=1===e.max&&d.length?[]:[...Object.keys(m),...a&&A?[f]:[]];return(0,o.jsx)(s.FormTokenField,{label:e.label,help:e.description,value:d,suggestions:O,onChange:l=>{if(l.find(e=>e===f)&&a&&!x)return g(!0),void w()({path:`/wp/v2/${e.taxonomy}`,method:"POST",data:S(n,v)}).then(e=>{const l=N(e,n),t=d.filter(e=>e!==f).concat(l),a=t.map(t=>p[t]??m[t]??(t===l?e.id:void 0)).filter(e=>void 0!==e);u(t=>({...t,[l]:e.id})),c(t),C(a)}).catch(()=>{}).finally(()=>g(!1));const t=l.filter(e=>void 0!==p[e]||void 0!==m[e]),i=t.map(e=>p[e]??m[e]);c(t),u(e=>({...e,...m})),C(i)},onInputChange:y,maxLength:e.max||void 0,id:e.name,__experimentalExpandOnFocus:!0})},location:({field:e,value:l,onChange:n})=>{const a=l||{},[i,r]=(0,b.useState)(a.address||""),[d,c]=(0,b.useState)([]),[p,u]=(0,b.useState)(!1),m=(0,t.useDebounce)(e=>{if(!e)return c([]);u(!0),w()({path:`jvb/v1/geocode?q=${encodeURIComponent(e)}`}).then(c).finally(()=>u(!1))},400);return(0,o.jsxs)("div",{className:"jvb-location-field",id:e.name,children:[(0,o.jsx)(s.TextControl,{label:e.label,value:i,onChange:e=>{r(e),m(e)}}),p&&(0,o.jsx)(s.Spinner,{}),!!d.length&&(0,o.jsxs)("div",{className:"jvb-location-results",children:[d.map(e=>(0,o.jsx)(s.Button,{variant:"tertiary",onClick:()=>(e=>{const l=e.address||{},t={address:[l.house_number,l.road].filter(Boolean).join(" "),city:l.city||l.town||l.village||"",province:l.state||"",postal_code:l.postcode||"",country:l.country||"",lat:parseFloat(e.lat),lng:parseFloat(e.lng)};n(t),r(t.address),c([])})(e),style:{display:"block",textAlign:"left"},children:e.display_name},e.place_id)),!!a.lat&&(0,o.jsxs)("p",{className:"jvb-location-summary",children:[a.address,", ",a.city,", ",a.province," ",a.postal_code,", ",a.country,(0,o.jsx)("br",{}),(0,o.jsx)(s.Button,{variant:"link",isDestructive:!0,onClick:()=>{n({}),r(""),c([])},children:"Clear"})]})]})]})},group:({field:e,value:l,onChange:t})=>{const n=l||{};return(0,o.jsxs)("div",{className:"jvb-group-field",id:e.name,children:[e.label&&(0,o.jsx)("h4",{className:"components-base-control__label",children:e.label}),Object.entries(e.fields||{}).map(([e,l])=>(0,o.jsx)(R,{field:{...l,name:e},value:n[e],onChange:l=>((e,l)=>{t({...n,[e]:l})})(e,l),meta:n},e)),e.description&&(0,o.jsx)("p",{className:"hint",children:e.description})]})}},O={"=":(e,l)=>e==l,"==":(e,l)=>e==l,"!=":(e,l)=>e!=l,">":(e,l)=>e>l,"<":(e,l)=>e<l,in:(e,l)=>Array.isArray(l)?l.includes(e):String(l).split(",").includes(e)},R=({id:e,field:l,value:t,onChange:n,meta:a})=>{if(!((e,l)=>!e?.field||(O[e.operator]||O["="])(l?.[e.field],e.value))(l.condition,a))return null;const i=A[l.type];return i?(0,o.jsx)(s.PanelRow,{children:(0,o.jsx)(i,{field:l,value:t,onChange:n})}):null},P=({id:e,name:l,fields:t,meta:n,setMeta:a,isOpen:i=!1})=>(e="jvb-section-"+e,(0,o.jsx)(s.PanelBody,{name:e,title:l,initialOpen:i,children:t.map(e=>(0,o.jsx)(R,{field:e,value:n?.[e.name],onChange:l=>((e,l)=>a({...n,[e]:l}))(e.name,l),meta:n},e.name))})),F=()=>(0,o.jsx)("svg",{xmlns:"http://www.w3.org/2000/svg",fillRule:"evenodd",strokeLinecap:"square",strokeLinejoin:"round",strokeMiterlimit:"1.5",clipRule:"evenodd",viewBox:"0 0 32 32",children:(0,o.jsx)("path",{fill:"currentColor",fillRule:"nonzero",d:"M16.58 2.133c-7.715 0-15.14 6.014-14.547 13.707.561 7.287 6.938 13.185 13.938 13.947 8.25.898 14.47-5.953 14.004-13.988-.447-7.7-5.683-13.666-13.395-13.666m0 .607h.031v26.492q-.285-.017-.574-.048c-6.724-.732-12.86-6.391-13.398-13.391C2.072 8.442 9.209 2.74 16.58 2.74m-.488 1.145L16 3.889c-3.275.13-6.448 1.476-8.744 3.611-2.297 2.135-3.716 5.065-3.463 8.346.492 6.384 6.071 11.538 12.201 12.207l.09.01.021-.182-.091-.01c-6.041-.66-11.555-5.755-12.04-12.04-.247-3.221 1.142-6.092 3.405-8.196s5.4-3.437 8.629-3.565l.092-.004zm0 1.502L16 5.39c-2.868.113-5.647 1.293-7.658 3.164-2.012 1.87-3.255 4.436-3.033 7.31.43 5.593 5.316 10.106 10.685 10.692l.09.01.021-.18-.091-.01c-5.28-.576-10.1-5.031-10.524-10.525-.217-2.815.997-5.325 2.975-7.164 1.978-1.84 4.72-3.004 7.543-3.116l.092-.004zm0 1.504L16 6.893c-2.462.097-4.846 1.111-6.572 2.716-1.727 1.606-2.796 3.808-2.606 6.276.37 4.8 4.564 8.674 9.172 9.177l.09.01.021-.181-.091-.01c-4.52-.494-8.648-4.307-9.01-9.01-.186-2.408.854-4.554 2.547-6.129s4.04-2.57 6.457-2.666l.092-.004zm0 1.502L16 8.396c-2.055.082-4.045.926-5.486 2.266-1.442 1.34-2.335 3.182-2.176 5.244.309 4.009 3.808 7.24 7.656 7.66l.09.01.008-.068v-.002l.002-.01.004-.01v-.02l.007-.072-.091-.01c-3.76-.41-7.193-3.58-7.494-7.491-.155-2.002.709-3.787 2.117-5.096s3.361-2.14 5.37-2.219l.093-.004zm0 1.502L16 9.898a6.95 6.95 0 0 0-4.402 1.819c-1.157 1.075-1.872 2.553-1.744 4.209.247 3.216 3.053 5.81 6.14 6.146l.09.01.021-.182-.091-.01c-2.999-.327-5.739-2.86-5.979-5.978-.123-1.595.564-3.018 1.688-4.062a6.78 6.78 0 0 1 4.285-1.77l.092-.004zm0 1.503L16 11.4a5.24 5.24 0 0 0-3.316 1.372c-.872.81-1.413 1.924-1.317 3.173.187 2.425 2.3 4.377 4.627 4.631l.09.01.021-.182-.091-.01c-2.238-.244-4.286-2.136-4.465-4.462-.092-1.19.421-2.248 1.26-3.028a5.06 5.06 0 0 1 3.199-1.32l.092-.004zm0 1.502-.092.004a3.52 3.52 0 0 0-2.23.92c-.587.546-.952 1.3-.887 2.143.126 1.633 1.545 2.942 3.111 3.113h-.008l.01.002h.01l.078.01.022-.182-.092-.01c-1.477-.16-2.831-1.412-2.95-2.947-.06-.782.277-1.48.83-1.994a3.35 3.35 0 0 1 2.114-.873l.092-.004zm0 1.502-.092.004c-.43.017-.843.192-1.145.473-.301.28-.49.67-.457 1.107.065.841.791 1.512 1.596 1.6l.09.01.021-.182-.091-.01c-.717-.078-1.377-.688-1.434-1.431-.029-.377.132-.712.4-.961.269-.25.644-.409 1.028-.424l.092-.004z",clipRule:"nonzero",overflow:"visible"})}),T=(0,n.withSelect)(e=>({metaFields:e("core/editor").getEditedPostAttribute("meta"),postType:e("core/editor").getCurrentPostType()})),D=(0,n.withDispatch)(e=>({setMetaFields(l){e("core/editor").editPost({meta:l})}})),z=({section:e,fields:l})=>l.filter(l=>e.fields.includes(l.name)),B=e=>0===e,L=(0,t.compose)([T,D])(({postType:e,metaFields:l,setMetaFields:t})=>{const{fields:n,sections:s}=window.jvbFieldConfig||{},[r,d]=(0,i.useEntityProp)("postType",e,"meta");return n&&n.length?(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(a.PluginSidebarMoreMenuItem,{target:"jvb-meta-fields",icon:(0,o.jsx)(F,{}),children:"Additional Fields"}),(0,o.jsx)(a.PluginSidebar,{name:"jvb-meta-fields",icon:(0,o.jsx)(F,{}),title:"Additional Fields",children:Object.values(s).map((e,l)=>(0,o.jsx)(P,{name:e.title,fields:z({section:e,fields:n}),meta:r,setMeta:d,isOpen:B(l)},e.id))})]}):null});(0,l.registerPlugin)("jvb-meta-fields",{render:L})})();
\ No newline at end of file
+(()=>{"use strict";const e={n:l=>{const t=l&&l.__esModule?()=>l.default:()=>l;return e.d(t,{a:t}),t},d:(l,t)=>{for(var n in t)e.o(t,n)&&!e.o(l,n)&&Object.defineProperty(l,n,{enumerable:!0,get:t[n]})},o:(e,l)=>Object.hasOwn(e,l)},l=window.wp.plugins,t=(window.wp.i18n,window.wp.compose),n=window.wp.data,a=window.wp.editor,i=window.wp.coreData,s=window.wp.components,o=window.ReactJSXRuntime,r={text:"text",email:"email",tel:"tel",url:"url",number:"number"},d=({field:e,value:l,onChange:t})=>"textarea"===e.type?(0,o.jsx)(s.TextareaControl,{label:e.label,help:e.description,value:l??"",onChange:t,id:e.name}):(0,o.jsx)(s.TextControl,{label:e.label,help:e.description,type:r[e.type]||"text",value:l??"",onChange:t,required:e.required,id:e.name}),c=({field:e,value:l,onChange:t})=>{const n=Object.entries(e.options||{}).map(([e,l])=>({label:l,value:e}));return"radio"===e.type?(0,o.jsx)(s.RadioControl,{label:e.label,help:e.description,selected:l,options:n,onChange:t,id:e.name}):(0,o.jsx)(s.SelectControl,{label:e.label,help:e.description,value:l??"",options:[{label:"— Select —",value:""},...n],onChange:t,id:e.name})},p=({field:e,value:l,onChange:t})=>{const n=Array.isArray(l)?l:[];return(0,o.jsxs)("fieldset",{id:e.name,children:[(0,o.jsx)("legend",{className:"jvb-field-label",children:e.label}),Object.entries(e.options||{}).map(([e,l])=>(0,o.jsx)(s.CheckboxControl,{label:l,checked:n.includes(e),onChange:l=>((e,l)=>{t(l?[...n,e]:n.filter(l=>l!==e))})(e,l)},e))]})},u=e=>{if(!e)return null;const[l,t,n]=e.split("-").map(Number);return l&&t&&n?new Date(l,t-1,n):null},m=e=>{if(e.description&&0!==e.description.length)return(0,o.jsx)("p",{className:"hint",children:e.description})},h=(window.React,e=>{if(e.description&&0!==e.description.length)return(0,o.jsx)("p",{className:"hint",children:e.description})}),v=window.wp.element,b=(e,l,t)=>e?.includes("{{")?e.replace(/{{(.*?)}}/g,(e,t)=>{const n=l[t];return void 0===n?"":Array.isArray(n)?n.join(", "):String(n)}):e,j=window.wp.mediaUtils,x=window.wp.blockEditor,g=window.wp.apiFetch;var f=e.n(g);const w={image:"image",video:"video",document:"application",all:""},y=({id:e,onRemove:l})=>{const[t,n]=(0,v.useState)(null);(0,v.useEffect)(()=>{let l=!1;if(e)return f()({path:`/wp/v2/media/${e}`}).then(e=>!l&&n(e)).catch(()=>{}),()=>{l=!0}},[e]);const a=t?.media_details?.sizes?.thumbnail?.source_url||t?.source_url,i="image"===t?.media_type;return(0,o.jsxs)("div",{className:"jvb-upload-thumb",children:[i&&a?(0,o.jsx)("img",{src:a,alt:t?.alt_text||""}):(0,o.jsx)("div",{className:"jvb-upload-thumb-placeholder",children:t?.title?.rendered||`#${e}`}),(0,o.jsx)(s.Button,{variant:"link",isDestructive:!0,onClick:()=>l(e),children:"Remove"})]})},C=window.wp.url,_=e=>e.subtype||e.type,k=(e,l,t)=>"post"===l?{title:t,status:"publish",postType:e.post_type}:{name:t},N=(e,l)=>"user"===l?e.name:e.title?.rendered??e.title??e.name,S={text:d,email:d,tel:d,url:d,number:d,textarea:d,select:c,radio:c,checkbox:p,set:p,true_false:({field:e,value:l,onChange:t})=>(0,o.jsx)(s.ToggleControl,{label:e.label,help:e.description,checked:!!l,onChange:t,id:e.name}),date:({field:e,value:l,onChange:t})=>(0,o.jsxs)("div",{className:"components-base-control",id:e.name,children:[(0,o.jsx)("label",{className:"components-base-control__label",children:e.label}),(0,o.jsx)(s.DatePicker,{currentDate:u(l),onChange:t,help:e.description}),m(e)]}),time:({field:e,value:l,onChange:t})=>(0,o.jsx)(s.BaseControl,{label:e.label,help:e.description,id:e.name,children:(0,o.jsx)("input",{type:"time",id:e.name,value:l??"",onChange:e=>t(e.target.value)})}),datetime:({field:e,value:l,onChange:t})=>(0,o.jsxs)("div",{className:"components-base-control",id:e.name,children:[(0,o.jsx)("label",{className:"components-base-control__label",children:e.label}),(0,o.jsx)(s.DateTimePicker,{currentDate:l||null,onChange:t,help:e.description,value:l??"",is12Hour:!0}),h(e)]}),repeater:({field:e,value:l,onChange:t,meta:n})=>{const a=Array.isArray(l)?l:[],i=e.fields||{},[r,d]=(0,v.useState)(null);return(0,o.jsxs)("div",{className:"jvb-repeater-field",id:e.name,children:[(0,o.jsx)("p",{className:"jvb-field-label",children:e.label}),(0,o.jsx)(s.Panel,{children:a.map((l,c)=>(0,o.jsxs)(s.PanelBody,{title:b(e.row_label,l)||`Row ${c+1}`,initialOpen:r===c,onToggle:()=>d(r===c?null:c),children:[Object.entries(i).map(([e,i])=>(0,o.jsx)(A,{field:{...i,name:e},value:l[e],onChange:l=>((e,l,n)=>{const i=a.map((t,a)=>a===e?{...t,[l]:n}:t);t(i)})(c,e,l),meta:n},e)),(0,o.jsx)(s.Button,{variant:"link",isDestructive:!0,onClick:()=>(e=>t(a.filter((l,t)=>t!==e)))(c),children:"Remove"})]},c))}),(0,o.jsx)(s.Button,{variant:"secondary",onClick:()=>{return t([...a,(e=i,Object.fromEntries(Object.entries(e||{}).map(([e,l])=>[e,l.default??""])))]);var e},children:e.add_label||"Add Row"})]})},upload:({field:e,value:l,onChange:t})=>{const n=e.multiple||"gallery"===e.type,a=n?"string"==typeof l&&l?l.split(",").map(Number):[]:l,i=w[e.subtype]?[w[e.subtype]]:"",r=e=>{t(n?a.filter(l=>l!==e).join(","):0)};return(0,o.jsxs)("div",{className:"jvb-upload-field",id:e.name,children:[(0,o.jsx)("p",{className:"jvb-field-label",children:e.label}),(0,o.jsx)("div",{className:n?"jvb-upload-grid":"jvb-upload-single",children:n?a.map(e=>(0,o.jsx)(y,{id:e,onRemove:r},e)):!!a&&(0,o.jsx)(y,{id:a,onRemove:r})}),(0,o.jsx)(x.MediaUploadCheck,{children:(0,o.jsx)(j.MediaUpload,{onSelect:e=>t(n?e.map(e=>e.id).join(","):e.id),allowedTypes:i,multiple:n,value:n?a:a||void 0,render:({open:l})=>(0,o.jsxs)(s.Button,{variant:"secondary",onClick:l,children:[(n?a.length:a)?"Change":"Select"," ",e.label]})})})]})},selector:({field:e,value:l,onChange:t})=>{const n=_(e),a="taxonomy"===n,i=(e=>{const l=_(e);return"user"===l?e=>(0,C.addQueryArgs)("/wp/v2/users",{search:e,per_page:20}):"taxonomy"===l?l=>(0,C.addQueryArgs)(`/wp/v2/${e.taxonomy}`,{search:l,per_page:20,hide_empty:!1}):l=>(0,C.addQueryArgs)("/wp/v2/search",{search:l,type:"post",subtype:e.post_type,per_page:20})})(e),r=Array.isArray(l)?l:l?l.split(","):[],[d,c]=(0,v.useState)([]),[p,u]=(0,v.useState)({}),[m,h]=(0,v.useState)({}),[b,j]=(0,v.useState)(""),[x,g]=(0,v.useState)(!1),w=b?`Not found. Create "${b}"?`:null;(0,v.useEffect)(()=>{y("");let e=!1;if(r.length)return Promise.all(r.map(e=>f()({path:i("")+`&include=${e}`}))).then(l=>{if(e)return;const t={},a=[];l.flat().forEach(e=>{const l=N(e,n);t[l]=e.id,a.push(l)}),u(e=>({...e,...t})),c(a)}).catch(()=>{}),()=>{e=!0};c([])},[JSON.stringify(r)]);const y=(0,v.useCallback)(e=>{j(e),f()({path:i(e)}).then(e=>{const l={};e.forEach(e=>{l[N(e,n)]=e.id}),h(l)}).catch(()=>{})},[i,n]),S=l=>{const n=1===e.max;t(n?l[l.length-1]??0:(e.max?l.slice(0,e.max):l).join(","))},O=b&&!Object.keys(m).some(e=>e.toLowerCase()===b.toLowerCase()),A=1===e.max&&d.length?[]:[...Object.keys(m),...a&&O?[w]:[]];return(0,o.jsx)(s.FormTokenField,{label:e.label,help:e.description,value:d,suggestions:A,onChange:l=>{if(l.find(e=>e===w)&&a&&!x)return g(!0),void f()({path:`/wp/v2/${e.taxonomy}`,method:"POST",data:k(e,n,b)}).then(e=>{const l=N(e,n),t=d.filter(e=>e!==w).concat(l),a=t.map(t=>p[t]??m[t]??(t===l?e.id:void 0)).filter(e=>void 0!==e);u(t=>({...t,[l]:e.id})),c(t),S(a)}).catch(()=>{}).finally(()=>g(!1));const t=l.filter(e=>void 0!==p[e]||void 0!==m[e]),i=t.map(e=>p[e]??m[e]);c(t),u(e=>({...e,...m})),S(i)},onInputChange:y,maxLength:e.max||void 0,id:e.name,__experimentalExpandOnFocus:!0})},location:({field:e,value:l,onChange:n})=>{const a=l||{},[i,r]=(0,v.useState)(a.address||""),[d,c]=(0,v.useState)([]),[p,u]=(0,v.useState)(!1),m=(0,t.useDebounce)(e=>{if(!e)return c([]);u(!0),f()({path:`jvb/v1/geocode?q=${encodeURIComponent(e)}`}).then(c).finally(()=>u(!1))},400);return(0,o.jsxs)("div",{className:"jvb-location-field",id:e.name,children:[(0,o.jsx)(s.TextControl,{label:e.label,value:i,onChange:e=>{r(e),m(e)}}),p&&(0,o.jsx)(s.Spinner,{}),!!d.length&&(0,o.jsxs)("div",{className:"jvb-location-results",children:[d.map(e=>(0,o.jsx)(s.Button,{variant:"tertiary",onClick:()=>(e=>{const l=e.address||{},t={address:[l.house_number,l.road].filter(Boolean).join(" "),city:l.city||l.town||l.village||"",province:l.state||"",postal_code:l.postcode||"",country:l.country||"",lat:parseFloat(e.lat),lng:parseFloat(e.lng)};n(t),r(t.address),c([])})(e),style:{display:"block",textAlign:"left"},children:e.display_name},e.place_id)),!!a.lat&&(0,o.jsxs)("p",{className:"jvb-location-summary",children:[a.address,", ",a.city,", ",a.province," ",a.postal_code,", ",a.country,(0,o.jsx)("br",{}),(0,o.jsx)(s.Button,{variant:"link",isDestructive:!0,onClick:()=>{n({}),r(""),c([])},children:"Clear"})]})]})]})},group:({field:e,value:l,onChange:t})=>{const n=l||{};return(0,o.jsxs)("div",{className:"jvb-group-field",id:e.name,children:[e.label&&(0,o.jsx)("h4",{className:"components-base-control__label",children:e.label}),Object.entries(e.fields||{}).map(([e,l])=>(0,o.jsx)(A,{field:{...l,name:e},value:n[e],onChange:l=>((e,l)=>{t({...n,[e]:l})})(e,l),meta:n},e)),e.description&&(0,o.jsx)("p",{className:"hint",children:e.description})]})}},O={"=":(e,l)=>e==l,"==":(e,l)=>e==l,"!=":(e,l)=>e!=l,">":(e,l)=>e>l,"<":(e,l)=>e<l,in:(e,l)=>Array.isArray(l)?l.includes(e):String(l).split(",").includes(e)},A=({id:e,field:l,value:t,onChange:n,meta:a})=>{if(!((e,l)=>!e?.field||(O[e.operator]||O["="])(l?.[e.field],e.value))(l.condition,a))return null;const i=S[l.type];return i?(0,o.jsx)(s.PanelRow,{children:(0,o.jsx)(i,{field:l,value:t,onChange:n})}):null},R=({id:e,name:l,fields:t,meta:n,setMeta:a,isOpen:i=!1})=>(e="jvb-section-"+e,(0,o.jsx)(s.PanelBody,{name:e,title:l,initialOpen:i,children:t.map(e=>(0,o.jsx)(A,{field:e,value:n?.[e.name],onChange:l=>((e,l)=>a({...n,[e]:l}))(e.name,l),meta:n},e.name))})),P=()=>(0,o.jsx)("svg",{xmlns:"http://www.w3.org/2000/svg",fillRule:"evenodd",strokeLinecap:"square",strokeLinejoin:"round",strokeMiterlimit:"1.5",clipRule:"evenodd",viewBox:"0 0 32 32",children:(0,o.jsx)("path",{fill:"currentColor",fillRule:"nonzero",d:"M16.58 2.133c-7.715 0-15.14 6.014-14.547 13.707.561 7.287 6.938 13.185 13.938 13.947 8.25.898 14.47-5.953 14.004-13.988-.447-7.7-5.683-13.666-13.395-13.666m0 .607h.031v26.492q-.285-.017-.574-.048c-6.724-.732-12.86-6.391-13.398-13.391C2.072 8.442 9.209 2.74 16.58 2.74m-.488 1.145L16 3.889c-3.275.13-6.448 1.476-8.744 3.611-2.297 2.135-3.716 5.065-3.463 8.346.492 6.384 6.071 11.538 12.201 12.207l.09.01.021-.182-.091-.01c-6.041-.66-11.555-5.755-12.04-12.04-.247-3.221 1.142-6.092 3.405-8.196s5.4-3.437 8.629-3.565l.092-.004zm0 1.502L16 5.39c-2.868.113-5.647 1.293-7.658 3.164-2.012 1.87-3.255 4.436-3.033 7.31.43 5.593 5.316 10.106 10.685 10.692l.09.01.021-.18-.091-.01c-5.28-.576-10.1-5.031-10.524-10.525-.217-2.815.997-5.325 2.975-7.164 1.978-1.84 4.72-3.004 7.543-3.116l.092-.004zm0 1.504L16 6.893c-2.462.097-4.846 1.111-6.572 2.716-1.727 1.606-2.796 3.808-2.606 6.276.37 4.8 4.564 8.674 9.172 9.177l.09.01.021-.181-.091-.01c-4.52-.494-8.648-4.307-9.01-9.01-.186-2.408.854-4.554 2.547-6.129s4.04-2.57 6.457-2.666l.092-.004zm0 1.502L16 8.396c-2.055.082-4.045.926-5.486 2.266-1.442 1.34-2.335 3.182-2.176 5.244.309 4.009 3.808 7.24 7.656 7.66l.09.01.008-.068v-.002l.002-.01.004-.01v-.02l.007-.072-.091-.01c-3.76-.41-7.193-3.58-7.494-7.491-.155-2.002.709-3.787 2.117-5.096s3.361-2.14 5.37-2.219l.093-.004zm0 1.502L16 9.898a6.95 6.95 0 0 0-4.402 1.819c-1.157 1.075-1.872 2.553-1.744 4.209.247 3.216 3.053 5.81 6.14 6.146l.09.01.021-.182-.091-.01c-2.999-.327-5.739-2.86-5.979-5.978-.123-1.595.564-3.018 1.688-4.062a6.78 6.78 0 0 1 4.285-1.77l.092-.004zm0 1.503L16 11.4a5.24 5.24 0 0 0-3.316 1.372c-.872.81-1.413 1.924-1.317 3.173.187 2.425 2.3 4.377 4.627 4.631l.09.01.021-.182-.091-.01c-2.238-.244-4.286-2.136-4.465-4.462-.092-1.19.421-2.248 1.26-3.028a5.06 5.06 0 0 1 3.199-1.32l.092-.004zm0 1.502-.092.004a3.52 3.52 0 0 0-2.23.92c-.587.546-.952 1.3-.887 2.143.126 1.633 1.545 2.942 3.111 3.113h-.008l.01.002h.01l.078.01.022-.182-.092-.01c-1.477-.16-2.831-1.412-2.95-2.947-.06-.782.277-1.48.83-1.994a3.35 3.35 0 0 1 2.114-.873l.092-.004zm0 1.502-.092.004c-.43.017-.843.192-1.145.473-.301.28-.49.67-.457 1.107.065.841.791 1.512 1.596 1.6l.09.01.021-.182-.091-.01c-.717-.078-1.377-.688-1.434-1.431-.029-.377.132-.712.4-.961.269-.25.644-.409 1.028-.424l.092-.004z",clipRule:"nonzero",overflow:"visible"})}),F=(0,n.withSelect)(e=>({metaFields:e("core/editor").getEditedPostAttribute("meta"),postType:e("core/editor").getCurrentPostType()})),T=(0,n.withDispatch)(e=>({setMetaFields(l){e("core/editor").editPost({meta:l})}})),z=({section:e,fields:l})=>l.filter(l=>e.fields.includes(l.name)),B=e=>0===e,D=(0,t.compose)([F,T])(({postType:e,metaFields:l,setMetaFields:t})=>{const{fields:n,sections:s}=window.jvbFieldConfig||{},[r,d]=(0,i.useEntityProp)("postType",e,"meta");return n&&n.length?(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(a.PluginSidebarMoreMenuItem,{target:"jvb-meta-fields",icon:(0,o.jsx)(P,{}),children:"Additional Fields"}),(0,o.jsx)(a.PluginSidebar,{name:"jvb-meta-fields",icon:(0,o.jsx)(P,{}),title:"Additional Fields",children:Object.values(s).map((e,l)=>(0,o.jsx)(R,{name:e.title,fields:z({section:e,fields:n}),meta:r,setMeta:d,isOpen:B(l)},e.id))})]}):null});(0,l.registerPlugin)("jvb-meta-fields",{render:D})})();
\ No newline at end of file
diff --git a/build/event/block.json b/build/event/block.json
new file mode 100644
index 0000000..e6a10ac
--- /dev/null
+++ b/build/event/block.json
@@ -0,0 +1,29 @@
+{
+ "$schema": "https://schemas.wp.org/trunk/block.json",
+ "apiVersion": 3,
+ "name": "jvb/event",
+ "title": "Event Summary",
+ "category": "jvb",
+ "icon": "align-center",
+ "description": "Outputs the event information",
+ "keywords": [
+ "event"
+ ],
+ "version": "0.9.0",
+ "textdomain": "jvb",
+ "supports": {
+ "html": false,
+ "align": [
+ "wide",
+ "full"
+ ]
+ },
+ "selectors": {
+ "root": ".event-block"
+ },
+ "render": "file:./render.php",
+ "editorScript": "file:./index.js",
+ "editorStyle": "file:./index.css",
+ "style": "file:./style-index.css",
+ "viewScript": "file:./view.js"
+}
\ No newline at end of file
diff --git a/build/event/index-rtl.css b/build/event/index-rtl.css
new file mode 100644
index 0000000..6cfd5fd
--- /dev/null
+++ b/build/event/index-rtl.css
@@ -0,0 +1 @@
+.jvb-summary-preview{background-color:#f8f9fa;border:1px solid #e2e4e7;border-radius:4px;padding:20px}.jvb-summary-preview h3{border-bottom:1px solid #ff0080;margin-top:0;padding-bottom:10px}.jvb-summary-preview-note{color:#555d66;font-style:italic;margin-bottom:0}
diff --git a/build/event/index.asset.php b/build/event/index.asset.php
new file mode 100644
index 0000000..992cc06
--- /dev/null
+++ b/build/event/index.asset.php
@@ -0,0 +1 @@
+<?php return array('dependencies' => array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-i18n'), 'version' => 'cb644be845ba8e59afd4');
diff --git a/build/event/index.css b/build/event/index.css
new file mode 100644
index 0000000..6cfd5fd
--- /dev/null
+++ b/build/event/index.css
@@ -0,0 +1 @@
+.jvb-summary-preview{background-color:#f8f9fa;border:1px solid #e2e4e7;border-radius:4px;padding:20px}.jvb-summary-preview h3{border-bottom:1px solid #ff0080;margin-top:0;padding-bottom:10px}.jvb-summary-preview-note{color:#555d66;font-style:italic;margin-bottom:0}
diff --git a/build/event/index.js b/build/event/index.js
new file mode 100644
index 0000000..75c0bb4
--- /dev/null
+++ b/build/event/index.js
@@ -0,0 +1 @@
+(()=>{"use strict";var e={391(){const e=window.wp.blocks,t=window.wp.i18n,n=window.wp.blockEditor,o=(window.wp.components,window.ReactJSXRuntime);(0,e.registerBlockType)("jvb/event",{edit:function({attributes:e,setAttributes:r}){const i=(0,n.useBlockProps)();return(0,o.jsx)("div",{...i,children:(0,o.jsxs)("div",{className:"jvb-summary-preview",children:[(0,o.jsx)("h3",{children:(0,t.__)("Summary","jvb")}),(0,o.jsx)("p",{className:"jvb-list-preview-note",children:(0,t.__)("This will inherit the current query to build the information from our custom meta on the front end.","jvb")})]})})},save:function(){return null}})}};const t={};function n(o){const r=t[o];if(void 0!==r)return r.exports;const i=t[o]={exports:{}};return e[o](i,i.exports,n),i.exports}n.m=e,(()=>{const e=[];n.O=(t,o,r,i)=>{if(o){i||=0;for(var s=e.length;s>0&&e[s-1][2]>i;s--)e[s]=e[s-1];return void(e[s]=[o,r,i])}let c=1/0;for(s=0;s<e.length;s++){let[o,r,i]=e[s],u=!0;for(var l=0;l<o.length;l++)1&i&&!(c>=i)||!Object.keys(n.O).every(e=>n.O[e](o[l]))?(u=!1,i<c&&(c=i)):o.splice(l--,1);if(u){e.splice(s--,1);const n=r();void 0!==n&&(t=n)}}return t}})(),n.o=(e,t)=>Object.hasOwn(e,t),(()=>{const e={188:0,44:0};n.O.j=t=>0===e[t];const t=(t,o)=>{let[r,i,s]=o;var c,l,u=0;if(r.some(t=>0!==e[t])){for(c in i)n.o(i,c)&&(n.m[c]=i[c]);if(s)var d=s(n)}for(t&&t(o);u<r.length;u++)l=r[u],n.o(e,l)&&e[l]&&e[l][0](),e[l]=0;return n.O(d)},o=globalThis.webpackChunkjvb||=[];o.forEach(t.bind(null,0)),o.push=t.bind(null,o.push.bind(o))})();let o=n.O(void 0,[44],()=>n(391));o=n.O(o)})();
\ No newline at end of file
diff --git a/build/event/render.php b/build/event/render.php
new file mode 100644
index 0000000..96762d8
--- /dev/null
+++ b/build/event/render.php
@@ -0,0 +1,5 @@
+<?php
+
+if (!defined('ABSPATH')) {
+ exit; // Exit if accessed directly
+}
diff --git a/build/event/style-index-rtl.css b/build/event/style-index-rtl.css
new file mode 100644
index 0000000..a9078f0
--- /dev/null
+++ b/build/event/style-index-rtl.css
@@ -0,0 +1 @@
+.event-block .tags{--gap:1rem}.event-block .tags .tag{background-color:rgb(var(--action-0));border-radius:4px;color:rgb(var(--action-contrast));display:flex;font-size:var(--txt-x-small);gap:.5rem;padding:.25rem .5rem 0;text-transform:uppercase}.event-block header{--wrap:nowrap!important;gap:1rem}.event-block header h1{margin:0}.event-block .calendar.col{border:2px solid rgb(var(--action-0));border-radius:.5rem;width:var(--btn_);--align:stretch;--gap:0}.event-block .calendar.col span{line-height:.8;text-align:center;text-transform:uppercase}.event-block .calendar.col .weekday{background-color:rgb(var(--action-0));color:rgb(var(--action-contrast));font-family:var(--heading);font-weight:var(--fw-h-bold);line-height:1.4;margin-bottom:.5rem}.event-block .calendar.col .day{font-size:var(--txt-xx-large)}.event-block .gallery figure{aspect-ratio:1;max-width:min(15vw,8rem)!important;object-fit:cover}.event-block figcaption{display:none}
diff --git a/build/event/style-index.css b/build/event/style-index.css
new file mode 100644
index 0000000..a9078f0
--- /dev/null
+++ b/build/event/style-index.css
@@ -0,0 +1 @@
+.event-block .tags{--gap:1rem}.event-block .tags .tag{background-color:rgb(var(--action-0));border-radius:4px;color:rgb(var(--action-contrast));display:flex;font-size:var(--txt-x-small);gap:.5rem;padding:.25rem .5rem 0;text-transform:uppercase}.event-block header{--wrap:nowrap!important;gap:1rem}.event-block header h1{margin:0}.event-block .calendar.col{border:2px solid rgb(var(--action-0));border-radius:.5rem;width:var(--btn_);--align:stretch;--gap:0}.event-block .calendar.col span{line-height:.8;text-align:center;text-transform:uppercase}.event-block .calendar.col .weekday{background-color:rgb(var(--action-0));color:rgb(var(--action-contrast));font-family:var(--heading);font-weight:var(--fw-h-bold);line-height:1.4;margin-bottom:.5rem}.event-block .calendar.col .day{font-size:var(--txt-xx-large)}.event-block .gallery figure{aspect-ratio:1;max-width:min(15vw,8rem)!important;object-fit:cover}.event-block figcaption{display:none}
diff --git a/build/event/view.asset.php b/build/event/view.asset.php
new file mode 100644
index 0000000..f534533
--- /dev/null
+++ b/build/event/view.asset.php
@@ -0,0 +1 @@
+<?php return array('dependencies' => array(), 'version' => '31d6cfe0d16ae931b73c');
diff --git a/build/event/view.js b/build/event/view.js
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/build/event/view.js
diff --git a/build/meta/index.asset.php b/build/meta/index.asset.php
index 3f6afe3..9e1d886 100644
--- a/build/meta/index.asset.php
+++ b/build/meta/index.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react', 'react-jsx-runtime', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-element', 'wp-media-utils', 'wp-url'), 'version' => '4fc77565e544173d57f5');
+<?php return array('dependencies' => array('react', 'react-jsx-runtime', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-element', 'wp-media-utils', 'wp-url'), 'version' => 'bd603a74c761d2467da8');
diff --git a/build/meta/index.js b/build/meta/index.js
index c97a964..9954f0d 100644
--- a/build/meta/index.js
+++ b/build/meta/index.js
@@ -1 +1 @@
-(()=>{"use strict";const e={n:l=>{const t=l&&l.__esModule?()=>l.default:()=>l;return e.d(t,{a:t}),t},d:(l,t)=>{for(var a in t)e.o(t,a)&&!e.o(l,a)&&Object.defineProperty(l,a,{enumerable:!0,get:t[a]})},o:(e,l)=>Object.hasOwn(e,l)},l=window.wp.blocks,t=window.wp.blockEditor,a=window.wp.components,n=window.wp.coreData,i=window.wp.data,s=window.ReactJSXRuntime,o={text:"text",email:"email",tel:"tel",url:"url",number:"number"},r=({field:e,value:l,onChange:t})=>"textarea"===e.type?(0,s.jsx)(a.TextareaControl,{label:e.label,help:e.description,value:l??"",onChange:t,id:e.name}):(0,s.jsx)(a.TextControl,{label:e.label,help:e.description,type:o[e.type]||"text",value:l??"",onChange:t,required:e.required,id:e.name}),d=({field:e,value:l,onChange:t})=>{const n=Object.entries(e.options||{}).map(([e,l])=>({label:l,value:e}));return"radio"===e.type?(0,s.jsx)(a.RadioControl,{label:e.label,help:e.description,selected:l,options:n,onChange:t,id:e.name}):(0,s.jsx)(a.SelectControl,{label:e.label,help:e.description,value:l??"",options:[{label:"— Select —",value:""},...n],onChange:t,id:e.name})},c=({field:e,value:l,onChange:t})=>{const n=Array.isArray(l)?l:[];return(0,s.jsxs)("fieldset",{id:e.name,children:[(0,s.jsx)("legend",{className:"jvb-field-label",children:e.label}),Object.entries(e.options||{}).map(([e,l])=>(0,s.jsx)(a.CheckboxControl,{label:l,checked:n.includes(e),onChange:l=>((e,l)=>{t(l?[...n,e]:n.filter(l=>l!==e))})(e,l)},e))]})},p=window.React,u=e=>{if(!e)return null;const[l,t,a]=e.split("-").map(Number);return new Date(l,t-1,a)},m=e=>{if(e.description&&0!==e.description.length)return(0,s.jsx)("p",{className:"hint",children:e.description})},h=e=>{if(e.description&&0!==e.description.length)return(0,s.jsx)("p",{className:"hint",children:e.description})},b=window.wp.element,v=(e,l,t)=>e?.includes("{{")?e.replace(/{{(.*?)}}/g,(e,t)=>{const a=l[t];return void 0===a?"":Array.isArray(a)?a.join(", "):String(a)}):e,j=window.wp.mediaUtils,x=window.wp.apiFetch;var f=e.n(x);const g={image:"image",video:"video",document:"application",all:""},y=({id:e,onRemove:l})=>{const[t,n]=(0,b.useState)(null);(0,b.useEffect)(()=>{let l=!1;if(e)return f()({path:`/wp/v2/media/${e}`}).then(e=>!l&&n(e)).catch(()=>{}),()=>{l=!0}},[e]);const i=t?.media_details?.sizes?.thumbnail?.source_url||t?.source_url,o="image"===t?.media_type;return(0,s.jsxs)("div",{className:"jvb-upload-thumb",children:[o&&i?(0,s.jsx)("img",{src:i,alt:t?.alt_text||""}):(0,s.jsx)("div",{className:"jvb-upload-thumb-placeholder",children:t?.title?.rendered||`#${e}`}),(0,s.jsx)(a.Button,{variant:"link",isDestructive:!0,onClick:()=>l(e),children:"Remove"})]})},C=window.wp.url,w=e=>e.subtype||e.type,S=(e,l,t)=>"post"===l?{title:t,status:"publish",postType:e.post_type}:{name:t},_=(e,l)=>"user"===l?e.name:e.title?.rendered??e.title??e.name,k=window.wp.compose,N={text:r,email:r,tel:r,url:r,number:r,textarea:r,select:d,radio:d,checkbox:c,set:c,true_false:({field:e,value:l,onChange:t})=>(0,s.jsx)(a.ToggleControl,{label:e.label,help:e.description,checked:!!l,onChange:t,id:e.name}),date:({field:e,value:l,onChange:t})=>(0,s.jsxs)("div",{className:"components-base-control",id:e.name,children:[(0,s.jsx)("label",{className:"components-base-control__label",children:e.label}),(0,s.jsx)(a.DatePicker,{currentDate:u(l),onChange:t,help:e.description}),m(e)]}),time:({field:e,value:l,onChange:t})=>(0,s.jsx)(a.BaseControl,{label:e.label,help:e.description,id:e.name,children:(0,s.jsx)("input",{type:"time",id:e.name,value:l??"",onChange:e=>t(e.target.value)})}),datetime:({field:e,value:l,onChange:t})=>{const[n,i]=(0,p.useState)(new Date);return(0,s.jsxs)("div",{className:"components-base-control",id:e.name,children:[(0,s.jsx)("label",{className:"components-base-control__label",children:e.label}),(0,s.jsx)(a.DateTimePicker,{currentDate:n,onChange:t,label:e.label,help:e.description,value:l??"",is12Hour:!0}),h(e)]})},repeater:({field:e,value:l,onChange:t,meta:n})=>{const i=Array.isArray(l)?l:[],o=e.fields||{},[r,d]=(0,b.useState)(null);return(0,s.jsxs)("div",{className:"jvb-repeater-field",id:e.name,children:[(0,s.jsx)("p",{className:"jvb-field-label",children:e.label}),(0,s.jsx)(a.Panel,{children:i.map((l,c)=>(0,s.jsxs)(a.PanelBody,{title:v(e.row_label,l)||`Row ${c+1}`,initialOpen:r===c,onToggle:()=>d(r===c?null:c),children:[Object.entries(o).map(([e,a])=>(0,s.jsx)(O,{field:{...a,name:e},value:l[e],onChange:l=>((e,l,a)=>{const n=i.map((t,n)=>n===e?{...t,[l]:a}:t);t(n)})(c,e,l),meta:n},e)),(0,s.jsx)(a.Button,{variant:"link",isDestructive:!0,onClick:()=>(e=>t(i.filter((l,t)=>t!==e)))(c),children:"Remove"})]},c))}),(0,s.jsx)(a.Button,{variant:"secondary",onClick:()=>{return t([...i,(e=o,Object.fromEntries(Object.entries(e||{}).map(([e,l])=>[e,l.default??""])))]);var e},children:e.add_label||"Add Row"})]})},upload:({field:e,value:l,onChange:n})=>{const i=e.multiple||"gallery"===e.type,o=i?Array.isArray(l)?l:[]:l,r=g[e.subtype]?[g[e.subtype]]:"",d=e=>{n(i?o.filter(l=>l!==e):0)};return(0,s.jsxs)("div",{className:"jvb-upload-field",id:e.name,children:[(0,s.jsx)("p",{className:"jvb-field-label",children:e.label}),(0,s.jsx)("div",{className:i?"jvb-upload-grid":"jvb-upload-single",children:i?o.map(e=>(0,s.jsx)(y,{id:e,onRemove:d},e)):!!o&&(0,s.jsx)(y,{id:o,onRemove:d})}),(0,s.jsx)(t.MediaUploadCheck,{children:(0,s.jsx)(j.MediaUpload,{onSelect:e=>n(i?e.map(e=>e.id):e.id),allowedTypes:r,multiple:i,value:i?o:o||void 0,render:({open:l})=>(0,s.jsxs)(a.Button,{variant:"secondary",onClick:l,children:[(i?o.length:o)?"Change":"Select"," ",e.label]})})})]})},selector:({field:e,value:l,onChange:t})=>{const n=w(e),i="taxonomy"===n,o=(e=>{const l=w(e);return"user"===l?e=>(0,C.addQueryArgs)("/wp/v2/users",{search:e,per_page:20}):"taxonomy"===l?l=>(0,C.addQueryArgs)(`/wp/v2/${e.taxonomy}`,{search:l,per_page:20,hide_empty:!1}):l=>(0,C.addQueryArgs)("/wp/v2/search",{search:l,type:"post",subtype:e.post_type,per_page:20})})(e),r=Array.isArray(l)?l:l?l.split(","):[],[d,c]=(0,b.useState)([]),[p,u]=(0,b.useState)({}),[m,h]=(0,b.useState)({}),[v,j]=(0,b.useState)(""),[x,g]=(0,b.useState)(!1),y=v?`Not found. Create "${v}"?`:null;(0,b.useEffect)(()=>{k("");let e=!1;if(r.length)return Promise.all(r.map(e=>f()({path:o("")+`&include=${e}`}))).then(l=>{if(e)return;const t={},a=[];l.flat().forEach(e=>{const l=_(e,n);t[l]=e.id,a.push(l)}),u(e=>({...e,...t})),c(a)}).catch(()=>{}),()=>{e=!0};c([])},[JSON.stringify(r)]);const k=(0,b.useCallback)(e=>{j(e),f()({path:o(e)}).then(e=>{const l={};e.forEach(e=>{l[_(e,n)]=e.id}),h(l)}).catch(()=>{})},[o,n]),N=l=>{const a=1===e.max;t(a?l[l.length-1]??0:(e.max?l.slice(0,e.max):l).join(","))},A=v&&!Object.keys(m).some(e=>e.toLowerCase()===v.toLowerCase()),O=1===e.max&&d.length?[]:[...Object.keys(m),...i&&A?[y]:[]];return(0,s.jsx)(a.FormTokenField,{label:e.label,help:e.description,value:d,suggestions:O,onChange:l=>{if(l.find(e=>e===y)&&i&&!x)return g(!0),void f()({path:`/wp/v2/${e.taxonomy}`,method:"POST",data:S(n,v)}).then(e=>{const l=_(e,n),t=d.filter(e=>e!==y).concat(l),a=t.map(t=>p[t]??m[t]??(t===l?e.id:void 0)).filter(e=>void 0!==e);u(t=>({...t,[l]:e.id})),c(t),N(a)}).catch(()=>{}).finally(()=>g(!1));const t=l.filter(e=>void 0!==p[e]||void 0!==m[e]),a=t.map(e=>p[e]??m[e]);c(t),u(e=>({...e,...m})),N(a)},onInputChange:k,maxLength:e.max||void 0,id:e.name,__experimentalExpandOnFocus:!0})},location:({field:e,value:l,onChange:t})=>{const n=l||{},[i,o]=(0,b.useState)(n.address||""),[r,d]=(0,b.useState)([]),[c,p]=(0,b.useState)(!1),u=(0,k.useDebounce)(e=>{if(!e)return d([]);p(!0),f()({path:`jvb/v1/geocode?q=${encodeURIComponent(e)}`}).then(d).finally(()=>p(!1))},400);return(0,s.jsxs)("div",{className:"jvb-location-field",id:e.name,children:[(0,s.jsx)(a.TextControl,{label:e.label,value:i,onChange:e=>{o(e),u(e)}}),c&&(0,s.jsx)(a.Spinner,{}),!!r.length&&(0,s.jsxs)("div",{className:"jvb-location-results",children:[r.map(e=>(0,s.jsx)(a.Button,{variant:"tertiary",onClick:()=>(e=>{const l=e.address||{},a={address:[l.house_number,l.road].filter(Boolean).join(" "),city:l.city||l.town||l.village||"",province:l.state||"",postal_code:l.postcode||"",country:l.country||"",lat:parseFloat(e.lat),lng:parseFloat(e.lng)};t(a),o(a.address),d([])})(e),style:{display:"block",textAlign:"left"},children:e.display_name},e.place_id)),!!n.lat&&(0,s.jsxs)("p",{className:"jvb-location-summary",children:[n.address,", ",n.city,", ",n.province," ",n.postal_code,", ",n.country,(0,s.jsx)("br",{}),(0,s.jsx)(a.Button,{variant:"link",isDestructive:!0,onClick:()=>{t({}),o(""),d([])},children:"Clear"})]})]})]})},group:({field:e,value:l,onChange:t})=>{const a=l||{};return(0,s.jsxs)("div",{className:"jvb-group-field",id:e.name,children:[e.label&&(0,s.jsx)("h4",{className:"components-base-control__label",children:e.label}),Object.entries(e.fields||{}).map(([e,l])=>(0,s.jsx)(O,{field:{...l,name:e},value:a[e],onChange:l=>((e,l)=>{t({...a,[e]:l})})(e,l),meta:a},e)),e.description&&(0,s.jsx)("p",{className:"hint",children:e.description})]})}},A={"=":(e,l)=>e==l,"==":(e,l)=>e==l,"!=":(e,l)=>e!=l,">":(e,l)=>e>l,"<":(e,l)=>e<l,in:(e,l)=>Array.isArray(l)?l.includes(e):String(l).split(",").includes(e)},O=({id:e,field:l,value:t,onChange:n,meta:i})=>{if(!((e,l)=>!e?.field||(A[e.operator]||A["="])(l?.[e.field],e.value))(l.condition,i))return null;const o=N[l.type];return o?(0,s.jsx)(a.PanelRow,{children:(0,s.jsx)(o,{field:l,value:t,onChange:n})}):null},P=JSON.parse('{"$schema":"https://schemas.wp.org/trunk/block.json","apiVersion":3,"name":"jvb/meta","version":"0.1.0","title":"Custom Field","category":"jvb","icon":"edit-large","description":"Add a specific field from this content","example":{},"attributes":{"fieldName":{"type":"string","default":""}},"supports":{"align":["wide","full"]},"textdomain":"jvb","selectors":{"root":".jvb-meta"},"editorScript":"file:./index.js","editorStyle":"file:./index.css","style":"file:./style-index.css","render":"file:./render.php","viewScript":"file:./view.js"}');(0,l.registerBlockType)(P,{edit:({attributes:e,setAttributes:l})=>{const{fieldName:o}=e,{fields:r}=window.jvbFieldConfig||{},d=(0,i.useSelect)(e=>e("core/editor").getCurrentPostType(),[]),[c,p]=(0,n.useEntityProp)("postType",d,"meta"),u=(r||[]).find(e=>e.name===o),m=(0,t.useBlockProps)();return(0,s.jsxs)("div",{...m,children:[(0,s.jsx)(t.InspectorControls,{children:(0,s.jsx)(a.PanelBody,{title:"Field",children:(0,s.jsx)(a.SelectControl,{label:"Meta field",value:o,options:[{label:"Select a field…",value:""},...(r||[]).map(e=>({label:e.label||e.name,value:e.name}))],onChange:e=>l({fieldName:e})})})}),!u&&(0,s.jsx)(a.Placeholder,{label:"Meta Field",instructions:"Select a field in the block settings."}),u&&(0,s.jsx)(O,{field:u,value:c?.[o],onChange:e=>p({...c,[o]:e}),meta:c})]})},save:()=>null})})();
\ No newline at end of file
+(()=>{"use strict";const e={n:l=>{const t=l&&l.__esModule?()=>l.default:()=>l;return e.d(t,{a:t}),t},d:(l,t)=>{for(var a in t)e.o(t,a)&&!e.o(l,a)&&Object.defineProperty(l,a,{enumerable:!0,get:t[a]})},o:(e,l)=>Object.hasOwn(e,l)},l=window.wp.blocks,t=window.wp.blockEditor,a=window.wp.components,n=window.wp.coreData,i=window.wp.data,s=window.ReactJSXRuntime,o={text:"text",email:"email",tel:"tel",url:"url",number:"number"},r=({field:e,value:l,onChange:t})=>"textarea"===e.type?(0,s.jsx)(a.TextareaControl,{label:e.label,help:e.description,value:l??"",onChange:t,id:e.name}):(0,s.jsx)(a.TextControl,{label:e.label,help:e.description,type:o[e.type]||"text",value:l??"",onChange:t,required:e.required,id:e.name}),d=({field:e,value:l,onChange:t})=>{const n=Object.entries(e.options||{}).map(([e,l])=>({label:l,value:e}));return"radio"===e.type?(0,s.jsx)(a.RadioControl,{label:e.label,help:e.description,selected:l,options:n,onChange:t,id:e.name}):(0,s.jsx)(a.SelectControl,{label:e.label,help:e.description,value:l??"",options:[{label:"— Select —",value:""},...n],onChange:t,id:e.name})},c=({field:e,value:l,onChange:t})=>{const n=Array.isArray(l)?l:[];return(0,s.jsxs)("fieldset",{id:e.name,children:[(0,s.jsx)("legend",{className:"jvb-field-label",children:e.label}),Object.entries(e.options||{}).map(([e,l])=>(0,s.jsx)(a.CheckboxControl,{label:l,checked:n.includes(e),onChange:l=>((e,l)=>{t(l?[...n,e]:n.filter(l=>l!==e))})(e,l)},e))]})},p=e=>{if(!e)return null;const[l,t,a]=e.split("-").map(Number);return l&&t&&a?new Date(l,t-1,a):null},u=e=>{if(e.description&&0!==e.description.length)return(0,s.jsx)("p",{className:"hint",children:e.description})},m=(window.React,e=>{if(e.description&&0!==e.description.length)return(0,s.jsx)("p",{className:"hint",children:e.description})}),h=window.wp.element,b=(e,l,t)=>e?.includes("{{")?e.replace(/{{(.*?)}}/g,(e,t)=>{const a=l[t];return void 0===a?"":Array.isArray(a)?a.join(", "):String(a)}):e,v=window.wp.mediaUtils,j=window.wp.apiFetch;var x=e.n(j);const f={image:"image",video:"video",document:"application",all:""},g=({id:e,onRemove:l})=>{const[t,n]=(0,h.useState)(null);(0,h.useEffect)(()=>{let l=!1;if(e)return x()({path:`/wp/v2/media/${e}`}).then(e=>!l&&n(e)).catch(()=>{}),()=>{l=!0}},[e]);const i=t?.media_details?.sizes?.thumbnail?.source_url||t?.source_url,o="image"===t?.media_type;return(0,s.jsxs)("div",{className:"jvb-upload-thumb",children:[o&&i?(0,s.jsx)("img",{src:i,alt:t?.alt_text||""}):(0,s.jsx)("div",{className:"jvb-upload-thumb-placeholder",children:t?.title?.rendered||`#${e}`}),(0,s.jsx)(a.Button,{variant:"link",isDestructive:!0,onClick:()=>l(e),children:"Remove"})]})},y=window.wp.url,C=e=>e.subtype||e.type,w=(e,l,t)=>"post"===l?{title:t,status:"publish",postType:e.post_type}:{name:t},_=(e,l)=>"user"===l?e.name:e.title?.rendered??e.title??e.name,k=window.wp.compose,N={text:r,email:r,tel:r,url:r,number:r,textarea:r,select:d,radio:d,checkbox:c,set:c,true_false:({field:e,value:l,onChange:t})=>(0,s.jsx)(a.ToggleControl,{label:e.label,help:e.description,checked:!!l,onChange:t,id:e.name}),date:({field:e,value:l,onChange:t})=>(0,s.jsxs)("div",{className:"components-base-control",id:e.name,children:[(0,s.jsx)("label",{className:"components-base-control__label",children:e.label}),(0,s.jsx)(a.DatePicker,{currentDate:p(l),onChange:t,help:e.description}),u(e)]}),time:({field:e,value:l,onChange:t})=>(0,s.jsx)(a.BaseControl,{label:e.label,help:e.description,id:e.name,children:(0,s.jsx)("input",{type:"time",id:e.name,value:l??"",onChange:e=>t(e.target.value)})}),datetime:({field:e,value:l,onChange:t})=>(0,s.jsxs)("div",{className:"components-base-control",id:e.name,children:[(0,s.jsx)("label",{className:"components-base-control__label",children:e.label}),(0,s.jsx)(a.DateTimePicker,{currentDate:l||null,onChange:t,help:e.description,value:l??"",is12Hour:!0}),m(e)]}),repeater:({field:e,value:l,onChange:t,meta:n})=>{const i=Array.isArray(l)?l:[],o=e.fields||{},[r,d]=(0,h.useState)(null);return(0,s.jsxs)("div",{className:"jvb-repeater-field",id:e.name,children:[(0,s.jsx)("p",{className:"jvb-field-label",children:e.label}),(0,s.jsx)(a.Panel,{children:i.map((l,c)=>(0,s.jsxs)(a.PanelBody,{title:b(e.row_label,l)||`Row ${c+1}`,initialOpen:r===c,onToggle:()=>d(r===c?null:c),children:[Object.entries(o).map(([e,a])=>(0,s.jsx)(A,{field:{...a,name:e},value:l[e],onChange:l=>((e,l,a)=>{const n=i.map((t,n)=>n===e?{...t,[l]:a}:t);t(n)})(c,e,l),meta:n},e)),(0,s.jsx)(a.Button,{variant:"link",isDestructive:!0,onClick:()=>(e=>t(i.filter((l,t)=>t!==e)))(c),children:"Remove"})]},c))}),(0,s.jsx)(a.Button,{variant:"secondary",onClick:()=>{return t([...i,(e=o,Object.fromEntries(Object.entries(e||{}).map(([e,l])=>[e,l.default??""])))]);var e},children:e.add_label||"Add Row"})]})},upload:({field:e,value:l,onChange:n})=>{const i=e.multiple||"gallery"===e.type,o=i?"string"==typeof l&&l?l.split(",").map(Number):[]:l,r=f[e.subtype]?[f[e.subtype]]:"",d=e=>{n(i?o.filter(l=>l!==e).join(","):0)};return(0,s.jsxs)("div",{className:"jvb-upload-field",id:e.name,children:[(0,s.jsx)("p",{className:"jvb-field-label",children:e.label}),(0,s.jsx)("div",{className:i?"jvb-upload-grid":"jvb-upload-single",children:i?o.map(e=>(0,s.jsx)(g,{id:e,onRemove:d},e)):!!o&&(0,s.jsx)(g,{id:o,onRemove:d})}),(0,s.jsx)(t.MediaUploadCheck,{children:(0,s.jsx)(v.MediaUpload,{onSelect:e=>n(i?e.map(e=>e.id).join(","):e.id),allowedTypes:r,multiple:i,value:i?o:o||void 0,render:({open:l})=>(0,s.jsxs)(a.Button,{variant:"secondary",onClick:l,children:[(i?o.length:o)?"Change":"Select"," ",e.label]})})})]})},selector:({field:e,value:l,onChange:t})=>{const n=C(e),i="taxonomy"===n,o=(e=>{const l=C(e);return"user"===l?e=>(0,y.addQueryArgs)("/wp/v2/users",{search:e,per_page:20}):"taxonomy"===l?l=>(0,y.addQueryArgs)(`/wp/v2/${e.taxonomy}`,{search:l,per_page:20,hide_empty:!1}):l=>(0,y.addQueryArgs)("/wp/v2/search",{search:l,type:"post",subtype:e.post_type,per_page:20})})(e),r=Array.isArray(l)?l:l?l.split(","):[],[d,c]=(0,h.useState)([]),[p,u]=(0,h.useState)({}),[m,b]=(0,h.useState)({}),[v,j]=(0,h.useState)(""),[f,g]=(0,h.useState)(!1),k=v?`Not found. Create "${v}"?`:null;(0,h.useEffect)(()=>{N("");let e=!1;if(r.length)return Promise.all(r.map(e=>x()({path:o("")+`&include=${e}`}))).then(l=>{if(e)return;const t={},a=[];l.flat().forEach(e=>{const l=_(e,n);t[l]=e.id,a.push(l)}),u(e=>({...e,...t})),c(a)}).catch(()=>{}),()=>{e=!0};c([])},[JSON.stringify(r)]);const N=(0,h.useCallback)(e=>{j(e),x()({path:o(e)}).then(e=>{const l={};e.forEach(e=>{l[_(e,n)]=e.id}),b(l)}).catch(()=>{})},[o,n]),S=l=>{const a=1===e.max;t(a?l[l.length-1]??0:(e.max?l.slice(0,e.max):l).join(","))},A=v&&!Object.keys(m).some(e=>e.toLowerCase()===v.toLowerCase()),O=1===e.max&&d.length?[]:[...Object.keys(m),...i&&A?[k]:[]];return(0,s.jsx)(a.FormTokenField,{label:e.label,help:e.description,value:d,suggestions:O,onChange:l=>{if(l.find(e=>e===k)&&i&&!f)return g(!0),void x()({path:`/wp/v2/${e.taxonomy}`,method:"POST",data:w(e,n,v)}).then(e=>{const l=_(e,n),t=d.filter(e=>e!==k).concat(l),a=t.map(t=>p[t]??m[t]??(t===l?e.id:void 0)).filter(e=>void 0!==e);u(t=>({...t,[l]:e.id})),c(t),S(a)}).catch(()=>{}).finally(()=>g(!1));const t=l.filter(e=>void 0!==p[e]||void 0!==m[e]),a=t.map(e=>p[e]??m[e]);c(t),u(e=>({...e,...m})),S(a)},onInputChange:N,maxLength:e.max||void 0,id:e.name,__experimentalExpandOnFocus:!0})},location:({field:e,value:l,onChange:t})=>{const n=l||{},[i,o]=(0,h.useState)(n.address||""),[r,d]=(0,h.useState)([]),[c,p]=(0,h.useState)(!1),u=(0,k.useDebounce)(e=>{if(!e)return d([]);p(!0),x()({path:`jvb/v1/geocode?q=${encodeURIComponent(e)}`}).then(d).finally(()=>p(!1))},400);return(0,s.jsxs)("div",{className:"jvb-location-field",id:e.name,children:[(0,s.jsx)(a.TextControl,{label:e.label,value:i,onChange:e=>{o(e),u(e)}}),c&&(0,s.jsx)(a.Spinner,{}),!!r.length&&(0,s.jsxs)("div",{className:"jvb-location-results",children:[r.map(e=>(0,s.jsx)(a.Button,{variant:"tertiary",onClick:()=>(e=>{const l=e.address||{},a={address:[l.house_number,l.road].filter(Boolean).join(" "),city:l.city||l.town||l.village||"",province:l.state||"",postal_code:l.postcode||"",country:l.country||"",lat:parseFloat(e.lat),lng:parseFloat(e.lng)};t(a),o(a.address),d([])})(e),style:{display:"block",textAlign:"left"},children:e.display_name},e.place_id)),!!n.lat&&(0,s.jsxs)("p",{className:"jvb-location-summary",children:[n.address,", ",n.city,", ",n.province," ",n.postal_code,", ",n.country,(0,s.jsx)("br",{}),(0,s.jsx)(a.Button,{variant:"link",isDestructive:!0,onClick:()=>{t({}),o(""),d([])},children:"Clear"})]})]})]})},group:({field:e,value:l,onChange:t})=>{const a=l||{};return(0,s.jsxs)("div",{className:"jvb-group-field",id:e.name,children:[e.label&&(0,s.jsx)("h4",{className:"components-base-control__label",children:e.label}),Object.entries(e.fields||{}).map(([e,l])=>(0,s.jsx)(A,{field:{...l,name:e},value:a[e],onChange:l=>((e,l)=>{t({...a,[e]:l})})(e,l),meta:a},e)),e.description&&(0,s.jsx)("p",{className:"hint",children:e.description})]})}},S={"=":(e,l)=>e==l,"==":(e,l)=>e==l,"!=":(e,l)=>e!=l,">":(e,l)=>e>l,"<":(e,l)=>e<l,in:(e,l)=>Array.isArray(l)?l.includes(e):String(l).split(",").includes(e)},A=({id:e,field:l,value:t,onChange:n,meta:i})=>{if(!((e,l)=>!e?.field||(S[e.operator]||S["="])(l?.[e.field],e.value))(l.condition,i))return null;const o=N[l.type];return o?(0,s.jsx)(a.PanelRow,{children:(0,s.jsx)(o,{field:l,value:t,onChange:n})}):null},O=JSON.parse('{"$schema":"https://schemas.wp.org/trunk/block.json","apiVersion":3,"name":"jvb/meta","version":"0.1.0","title":"Custom Field","category":"jvb","icon":"edit-large","description":"Add a specific field from this content","example":{},"attributes":{"fieldName":{"type":"string","default":""}},"supports":{"align":["wide","full"]},"textdomain":"jvb","selectors":{"root":".jvb-meta"},"editorScript":"file:./index.js","editorStyle":"file:./index.css","style":"file:./style-index.css","render":"file:./render.php","viewScript":"file:./view.js"}');(0,l.registerBlockType)(O,{edit:({attributes:e,setAttributes:l})=>{const{fieldName:o}=e,{fields:r}=window.jvbFieldConfig||{},d=(0,i.useSelect)(e=>e("core/editor").getCurrentPostType(),[]),[c,p]=(0,n.useEntityProp)("postType",d,"meta"),u=(r||[]).find(e=>e.name===o),m=(0,t.useBlockProps)();return(0,s.jsxs)("div",{...m,children:[(0,s.jsx)(t.InspectorControls,{children:(0,s.jsx)(a.PanelBody,{title:"Field",children:(0,s.jsx)(a.SelectControl,{label:"Meta field",value:o,options:[{label:"Select a field…",value:""},...(r||[]).map(e=>({label:e.label||e.name,value:e.name}))],onChange:e=>l({fieldName:e})})})}),!u&&(0,s.jsx)(a.Placeholder,{label:"Meta Field",instructions:"Select a field in the block settings."}),u&&(0,s.jsx)(A,{field:u,value:c?.[o],onChange:e=>p({...c,[o]:e}),meta:c})]})},save:()=>null})})();
\ No newline at end of file
diff --git a/build/simple-calendar/index.asset.php b/build/simple-calendar/index.asset.php
index fd4d50f..b0acfbb 100644
--- a/build/simple-calendar/index.asset.php
+++ b/build/simple-calendar/index.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-i18n'), 'version' => 'e8eefb198c6c47107fc4');
+<?php return array('dependencies' => array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-i18n'), 'version' => 'c9d53040b1ae8b423795');
diff --git a/build/simple-calendar/style-index-rtl.css b/build/simple-calendar/style-index-rtl.css
index 96a9eeb..6b1fe8f 100644
--- a/build/simple-calendar/style-index-rtl.css
+++ b/build/simple-calendar/style-index-rtl.css
@@ -1 +1 @@
-p.empty{background-color:rgb(var(--base));border:2px dashed rgba(var(--base-200));border-radius:var(--radius);font-style:italic;text-align:center}details{margin:2rem 0}details h2{margin:0}
+p.empty{background-color:rgb(var(--base));border:2px dashed rgba(var(--base-200));border-radius:var(--radius);font-style:italic;text-align:center}details{margin:2rem 0}details h2{margin:0}nav.calendar.types.types{height:max-content}
diff --git a/build/simple-calendar/style-index.css b/build/simple-calendar/style-index.css
index 96a9eeb..6b1fe8f 100644
--- a/build/simple-calendar/style-index.css
+++ b/build/simple-calendar/style-index.css
@@ -1 +1 @@
-p.empty{background-color:rgb(var(--base));border:2px dashed rgba(var(--base-200));border-radius:var(--radius);font-style:italic;text-align:center}details{margin:2rem 0}details h2{margin:0}
+p.empty{background-color:rgb(var(--base));border:2px dashed rgba(var(--base-200));border-radius:var(--radius);font-style:italic;text-align:center}details{margin:2rem 0}details h2{margin:0}nav.calendar.types.types{height:max-content}
diff --git a/inc/blocks/EventBlock.php b/inc/blocks/EventBlock.php
new file mode 100644
index 0000000..acfd31e
--- /dev/null
+++ b/inc/blocks/EventBlock.php
@@ -0,0 +1,300 @@
+<?php
+namespace JVBase\blocks;
+
+
+use DateTime;
+use JVBase\meta\Meta;
+use JVBase\utility\Image;
+use WP_Block;
+
+if (!defined('ABSPATH')) {
+ exit;
+}
+
+class EventBlock {
+ public function __construct()
+ {
+ add_action('init', [$this, 'registerBlock']);
+ }
+
+ public function registerBlock():void
+ {
+ register_block_type(
+ JVB_DIR . '/build/event',
+ [
+ 'render_callback' => [$this, 'render']
+ ]
+ );
+ }
+
+ public function render(array $attributes, string $content, WP_Block $block):string
+ {
+
+ if (!is_singular(BASE.'event')) {
+ return '';
+ }
+
+ $meta = Meta::forPost(get_the_ID());
+ $values = $meta->getAll();
+
+ $out = '<section class="event-block">';
+ $out .= '<div class="event tags row right">';
+ $get = ['is_free' => 'Free', 'rsvp_required' => 'Must RSVP', 'public' => 'Private Event'];
+ foreach ($get as $k => $g) {
+ $check = !empty($values[$k]) && $values[$k] === '1';
+ if ($k === 'public') {
+ $check = !$check;
+ }
+ $icon = match ($k) {
+ 'is_free' => jvbIcon('check-circle'),
+ 'rsvp_required' => jvbIcon('envelope'),
+ 'public' => jvbIcon('lock-key'),
+ };
+ if ($check) {
+ $out .= sprintf(
+ '<div class="tag">%s%s</div>',
+ $icon,
+ $g
+ );
+ }
+ }
+ $out .= '</div>';
+ if (!empty($values['post_thumbnail'])) {
+ $out .= jvbFormatImage($values['post_thumbnail']);
+ }
+ $out .= '<header class="row x-btw">';
+ if (!empty($values['post_title'])) {
+ $out .= sprintf(
+ '<h1 id="%s">%s</h1>',
+ sanitize_title($values['post_title']),
+ $values['post_title']
+ );
+ }
+ $out .= $this->calendarDay($values['date_start']??'');
+
+ $out .= '</header>';
+
+ $out .= '<div class="meta">';
+ $out .= sprintf(
+ '<ul class="time term-list row left"><li class="title">%s</li>',
+ jvbIcon('clock')
+ );
+ $out .= $this->formatDay($values['date_start']??'', $values['time_start']??'', $values['time_end']??'');
+ foreach ($values['schedule']??[] as $date) {
+ $out .= $this->formatDay($date['date'], $date['time_start'], $date['time_end'], $date['notes']);
+ }
+ $out .= '</ul>';
+
+ $out .= $this->location($values['location']??[], $values['location_notes']??'');
+
+ $out .= $this->price($values['cost']??'', $values['ticket_url']??'');
+ $out .= $this->participants($values['max_participants']??'');
+
+ $get = ['city', 'event_category'];
+ foreach ($get as $g) {
+ if (!empty($values[$g])) {
+ $out .= jvbMetaTermList($values[$g], $g);
+ }
+ }
+
+ $out .= $this->rsvp($values['rsvp_required']??'', $values['rsvp_limit']??'', $values['rsvp_deadline']);
+
+ $out .= '</div>';
+ $out .= $this->gallery($values['gallery']??'');
+ $out .= $this->moreInfo($values['external_url']??'');
+
+ $out .= '</section>';
+ return $out;
+ }
+ public function renderGallery():void
+ {
+ jvbRenderGallery();
+ }
+
+ protected function calendarDay(string $day):string
+ {
+ $out = '';
+ if (!empty($day)) {
+ $date = new DateTime($day, wp_timezone());
+ $weekday = $date->format('D');
+ $num = $date->format('d');
+ $month = $date->format('M');
+
+ $out .= sprintf(
+ '<div class="col calendar">
+ <span class="weekday">%s</span>
+ <span class="month">%s</span>
+ <span class="day">%d</span>
+ </div>',
+ $weekday,
+ $month,
+ $num
+ );
+ }
+ return $out;
+ }
+ protected function renderLocationString(array $location):string
+ {
+ if (!array_key_exists('address', $location) ||
+ !array_key_exists('street', $location) ||
+ !array_key_exists('city', $location) ||
+ !array_key_exists('province', $location) ||
+ !array_key_exists('country', $location)) {
+ return '';
+ }
+
+ return sprintf(
+ '<p class="location">%s%s<br>%s, %s %s</p>',
+ $location['address'],
+ $location['street'],
+ $location['city'],
+ $location['province'],
+ $location['country'] === 'CA' ? '' : $location['country']
+ );
+ }
+
+ protected function formatDay(string $date, string $start, string $end, string $notes = ''):string
+ {
+ $out = '<li>';
+ if (!empty($date)) {
+ $out .= sprintf(
+ '<time datetime="%s">%s</time><br>',
+ date('c', strtotime($date)),
+ date('F j, Y', strtotime($date))
+ );
+ }
+ $doit = false;
+
+ if (!empty($start)) {
+ $doit = true;
+ $d = strtotime($date.' '.$start);
+ $out .= sprintf(
+ '<time datetime="%s">%s</time>',
+ date('c', $d),
+ date('g:ia', $d)
+ );
+ }
+ if (!empty($end)) {
+ if ($doit) {
+ $out .= ' - ';
+ }
+ $d = strtotime($date.' '.$end);
+ $out .= sprintf(
+ '<time datetime="%s">%s</time>',
+ date('c', $d),
+ date('g:ia', $d)
+ );
+
+ }
+ if (!empty($notes)) {
+ $out .= wpautop($notes);
+ }
+
+ $out .= '</li>';
+ return $out;
+ }
+
+ protected function location(array $location, string $notes = ''):string
+ {
+ $out = '';
+ if (!empty($location['address']??'')) {
+ $out .= sprintf(
+ '<ul class="location term-list row left">
+ <li class="title">%sLocation</li>
+ <li>%s</li>
+ <li>%s</li>
+ %s
+ </ul>',
+ jvbIcon('map-pin'),
+ $this->renderLocationString($location),
+ jvbLocationLinks($location),
+ empty($notes) ? '' : '<li>'.$notes.'</li>',
+ );
+ }
+ return $out;
+ }
+
+ protected function price(string $price, string $url):string
+ {
+ $out = '';
+ if (!empty($price) || $price !== '0') {
+ $out = jvbCurrency($price);
+ }
+ if (!empty($url)) {
+ $out .= sprintf(
+ '<br><a href="%s">%sPurchase Tickets</a>',
+ esc_url($url),
+ jvbIcon('ticket')
+ );
+ }
+ return empty($out) ? $out : '<p>'.$out.'</p>';
+ }
+
+ protected function participants(string $num):string
+ {
+ $out = '';
+ if (!empty($num) || $num !== '0') {
+ $out .= sprintf(
+ '<p>Maximum %d participants</p>',
+ $num
+ );
+ }
+ return $out;
+ }
+
+ protected function moreInfo(string $url):string
+ {
+ $out = '';
+ if (!empty($url)) {
+ $out .= sprintf(
+ '<p>%s<a href="%s" target="_blank">Learn More</a></p>',
+ jvbIcon('link'),
+ esc_url($url)
+ );
+ }
+ return $out;
+ }
+
+ protected function rsvp(string $mustRSVP, string $limit, string $deadline):string
+ {
+ $out = '';
+ if (!empty($mustRSVP) && $mustRSVP === '1') {
+ $out = '<p class="rsvp">RSVP Required';
+ if (!empty($limit) && $limit !== '0') {
+ $out .= sprintf(
+ '<br>Maximum %d Seats',
+ $limit
+ );
+ }
+ if (!empty($deadline)) {
+ $out .= sprintf(
+ '<br>RSVP Deadline: <time datetime="%s">%s</time>',
+ date('c', $deadline),
+ date('F j, Y', $deadline)
+ );
+ }
+ $out .= '</p>';
+ }
+ return $out;
+ }
+
+ protected function gallery(string $gallery):string
+ {
+ $out = '';
+ if (!empty($gallery)) {
+ add_action('wp_footer', [$this, 'renderGallery']);
+ $out = '<div class="gallery row left">';
+ $gallery = array_map('absint', explode(',', $gallery));
+ foreach ($gallery as $id) {
+ $caption = wp_get_attachment_caption($id);
+ $out .= sprintf(
+ '<figure>%s<figcaption>%s</figcaption></figure>',
+ jvbFormatImage($id,'tiny','medium',true,'event'),
+ empty($caption) ? '' : $caption
+ );
+ }
+ $out .= '</div>';
+ }
+ return $out;
+ }
+}
diff --git a/inc/blocks/FAQBlock.php b/inc/blocks/FAQBlock.php
index f39d98f..d218b17 100644
--- a/inc/blocks/FAQBlock.php
+++ b/inc/blocks/FAQBlock.php
@@ -24,7 +24,8 @@
/**
* Register the FAQ block
*/
- public function registerBlock() {
+ public function registerBlock():void
+ {
// Register the block
register_block_type(
JVB_DIR . '/build/faq',
@@ -125,7 +126,7 @@
* @param WP_Block $block Block instance
* @return string Rendered block HTML
*/
- public function render($attributes, $content, $block)
+ public function render(array $attributes, string $content, WP_Block $block):string
{
ob_start();
?>
diff --git a/inc/blocks/MenuBlock.php b/inc/blocks/MenuBlock.php
index b1d7347..79be975 100644
--- a/inc/blocks/MenuBlock.php
+++ b/inc/blocks/MenuBlock.php
@@ -47,7 +47,7 @@
if (wp_is_post_revision($postID) || wp_is_post_autosave($postID)) return;
$postType = $post->post_type;
- if ($postType !== 'product' && !in_array($postType, Registrar::getFoodMenuTypes())) {
+ if ($postType !== 'product' || !in_array($postType, Registrar::getFoodMenuTypes())) {
return;
}
error_log('Flushing food menu block cache');
diff --git a/inc/blocks/SimpleCalendarBlock.php b/inc/blocks/SimpleCalendarBlock.php
index e294792..c83d0a3 100644
--- a/inc/blocks/SimpleCalendarBlock.php
+++ b/inc/blocks/SimpleCalendarBlock.php
@@ -1,6 +1,7 @@
<?php
namespace JVBase\blocks;
+use DateTime;
use JVBase\managers\Cache;
use JVBase\meta\Meta;
use JVBase\registrar\Registrar;
@@ -31,6 +32,7 @@
public function __construct()
{
$this->cache = Cache::for('calendar', 'post', DAY_IN_SECONDS);
+ $this->cache->flush();
add_action('init', [ $this, 'registerBlock' ]);
}
@@ -73,6 +75,14 @@
} else {
$this->params = [];
}
+
+ foreach (['eyear', 'emonth', 'eday'] as $key) {
+ $val = get_query_var($key);
+ if (!empty($val)) {
+ $this->params[$key] = $val;
+ }
+ }
+
}
public function render(array $attributes, string $content, WP_Block $block)
@@ -95,19 +105,20 @@
protected function renderBlock():void
{
+ echo '<section class="simple-calendar">';
$this->renderHeader();
$this->renderCalendar();
$this->renderOnThisPage();
+ echo '</section>';
}
protected function renderHeader():void
{
- $title = 'Events';
- if(!in_array('all', $this->params)) {
- $title = '<small>'.$title.'</small>';
- }
+ $title = $this->determineTitle();
+
?>
+
<header id="top">
<h1><?=$title?></h1>
<?php $this->buildNav(); ?>
@@ -118,6 +129,50 @@
</section>
<?php
}
+ protected function determineTitle():string
+ {
+ if (is_tax(BASE.'event_category')) {
+ $title = sprintf(
+ '%s Events',
+ get_queried_object()->name,
+ );
+ } else {
+ $title = 'Events';
+ }
+
+
+ if(!in_array('all', $this->params)) {
+ $title = '<small>'.$title.'</small>';
+ }
+ if (is_tax(BASE.'city')) {
+ $title .= sprintf(
+ ' in %s',
+ get_queried_object()->name,
+ );
+ }
+ if ($this->has('emonth')) {
+ $title .= sprintf(
+ ' %s %s',
+ is_tax() ? 'happening on' : 'in',
+ $this->getMonthName((int)$this->has('emonth')),
+ );
+ }
+ if ($this->has('eday')) {
+ $title .= sprintf(
+ ' %s,',
+ (int)$this->has('eday')
+ );
+ }
+ if ($this->has('eyear')) {
+ $title.= sprintf(
+ ' %s%s',
+ !$this->has('emonth') ? 'in ' : '',
+ $this->has('eyear')
+ );
+ }
+
+ return $title;
+ }
protected function buildNav():void
{
$content = $taxonomies = '';
@@ -159,7 +214,7 @@
}
if (!empty($out)) {
$taxonomies .= sprintf(
- '<ul class="term-list %s"><li class="label">%s</li>%s</ul>',
+ '<ul class="term-list row start %s"><li class="label">%s</li>%s</ul>',
$slug,
$title,
implode('', $out)
@@ -168,14 +223,109 @@
}
}
- if (!empty($content) || !empty($taxonomies)) {
+ $dates = $this->getDateNavigation();
+
+ if (!is_post_type_archive($this->content[0]) || $this->isDatedArchive()) {
echo sprintf(
- '<nav class="types">%s%s</nav>',
+ '<a href="%s" class="btn chip">All Events</a>',
+ get_post_type_archive_link($this->content[0])
+ );
+ }
+ if (!empty($content) || !empty($taxonomies) || !empty($dates)) {
+ echo sprintf(
+ '<nav class="calendar types">%s%s%s</nav>',
$content,
- $taxonomies
+ $taxonomies,
+ $dates
);
}
}
+ protected function isDatedArchive():bool
+ {
+ foreach (['eyear', 'emonth', 'eday'] as $key) {
+ if (array_key_exists($key, $this->params)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ protected function getDateNavigation():string
+ {
+ $type = get_post_type();
+ if (empty($type)) {
+ return '';
+ }
+
+ return $this->cache->remember(
+ $type.'dateNav',
+ function() use ($type) {
+ $tmp = new WP_Query([
+ 'post_type' => $type,
+ 'post_status' => 'publish',
+ 'posts_per_page' => -1,
+ 'fields' => 'ids',
+ ]);
+ $dates = [];
+ foreach ($tmp->posts as $id) {
+ $meta = Meta::forPost($id);
+ $start = $meta->get('date_start');
+ if (!empty($start)) {
+ $date = new DateTime($start);
+ $year = $date->format('Y');
+ $month = $date->format('m');
+ $day = $date->format('d');
+
+ if (!array_key_exists($year, $dates)) {
+ $dates[$year] = [];
+ }
+ if (!array_key_exists($month, $dates[$year])) {
+ $dates[$year][$month] = [];
+ }
+ if (!in_array($day, $dates[$year][$month])) {
+ $dates[$year][$month][] = $day;
+ }
+ }
+ }
+ if (empty($dates)) {
+ return '';
+ }
+
+ $base = get_post_type_archive_link($type);
+ $out = sprintf(
+ '<details class="dates row start"><summary>%sBy Date</summary>',
+ jvbIcon('calendar')
+ );
+ foreach ($dates as $year => $months) {
+ $out .= sprintf(
+ '<details><summary><a href="%s/%d" title="See all in %d">%d</a></summary><ul>',
+ $base,
+ $year,
+ $year,
+ $year
+ );
+
+ foreach ($months as $month => $days) {
+ $m = intval($month);
+ $monthName = $this->getMonthName($m);
+
+ $out .= sprintf(
+ '<li><a href="%s/%d/%s" title="View all posts in %s, %d">%s</a></li>',
+ $base,
+ $year,
+ $month,
+ $monthName,
+ $year,
+ $monthName
+ );
+ }
+ $out .= '</ul></details>';
+ }
+ $out .= '</details>';
+
+ return $out;
+ }
+ );
+ }
protected function renderCalendar():void
{
@@ -201,7 +351,7 @@
}
if (is_tax()) {
$tax = get_queried_object();
- jvbDump($tax);
+ jvbDump($tax, 'taxonomy');
}
return [];
}
@@ -213,27 +363,7 @@
return $this->formatSingular();
}
- $page = $past
- ? $_GET['jpast']??1
- : $_GET['jpage']??1;
-
- $items = new WP_Query([
- 'post_type' =>$this->getCurrentPostTypes(),
- 'post_status' => 'publish',
- 'orderby' => 'meta_value',
- 'meta_key' => BASE.'date_start',
- 'posts_per_page'=> 30,
- 'fields' => 'ids',
- 'paged' => $page,
- 'meta_type' => 'DATETIME',
- 'meta_query' => [
- [
- 'key' => BASE.'past',
- 'value' => '1',
- 'compare' => $past ? '=' : '!='
- ]
- ]
- ]);
+ $items = new WP_Query($this->buildArgs($past));
$events = implode('', array_map([$this, 'formatItem'], $items->posts));
@@ -248,19 +378,78 @@
$events .= paginate_links([
'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
'format' => '?'.$format.'=%#%',
- 'current' => $page,
+ 'current' => $items->query_vars['paged'],
'total' => $total
]);
}
+ wp_reset_postdata();
+
return $events;
}
+ protected function buildArgs(bool $past):array
+ {
+ $page = $past
+ ? min($_GET['jpast']??1, 1)
+ : min($_GET['jpage']??1, 1);
+ $postTypes = $this->getCurrentPostTypes();
+
+ $args = [
+ 'post_type' => $postTypes,
+ 'post_status' => 'publish',
+ 'orderby' => 'meta_value',
+ 'meta_key' => BASE.'date_start',
+ 'meta_type' => 'DATETIME',
+ 'posts_per_page'=> 30,
+ 'fields' => 'ids',
+ 'paged' => $page,
+ 'meta_query' => [
+ [
+ 'key' => BASE.'past',
+ 'value' => '1',
+ 'compare' => $past ? 'EXISTS' : 'NOT EXISTS'
+ ]
+ ]
+ ];
+
+
+ if ($this->has('eyear')) {
+ $args['meta_query'][] = [
+ 'key' => BASE.'year',
+ 'value' => intval($this->has('eyear')),
+ ];
+ }
+ if ($this->has('emonth')) {
+ $args['meta_query'][] = [
+ 'key' => BASE.'month',
+ 'value' => str_pad($this->has('emonth'), 2, "0", STR_PAD_LEFT),
+ ];
+ }
+ if ($this->has('eday')) {
+ $args['meta_query'][] = [
+ 'key' => BASE.'day',
+ 'value' => str_pad($this->has('eday'), 2, "0", STR_PAD_LEFT),
+ ];
+ }
+ if (is_tax()) {
+ $obj = get_queried_object();
+ $args['tax_query']= [
+ [
+ 'taxonomy' => $obj->taxonomy,
+ 'terms' => $obj->term_id,
+ ]
+ ];
+ }
+ return $args;
+ }
+
protected function formatItem(int $ID):string
{
$meta = Meta::forPost($ID);
$type = jvbNoBase(get_post_type($ID));
+ $date = strtotime($meta->get('date_start'));
return sprintf(
'<li class="item %s">
%s
@@ -274,8 +463,8 @@
empty($meta->get('post_thumbnail')) ? '' : jvbFormatImage($meta->get('post_thumbnail'), 'tiny', 'medium'),
get_the_permalink($ID),
$meta->get('post_title'),
- date('c', $meta->get('date_start')),
- date('F j, Y', $meta->get('date_start')),
+ date('c', $date),
+ date('F j, Y', $date),
empty($meta->get('post_excerpt')) ? '' : wpautop($meta->get('post_excerpt'))
);
}
@@ -293,4 +482,29 @@
}
echo jvbOnThisPage(array_keys($this->details));
}
+
+ protected function has(string $key):false|string
+ {
+ return array_key_exists($key, $this->params) && absint($this->params[$key]) > 0 ?
+ $this->params[$key] :
+ false;
+ }
+
+ protected function getMonthName(int $num):string
+ {
+ return match($num) {
+ 1 => 'January',
+ 2 => 'February',
+ 3 => 'March',
+ 4 => 'April',
+ 5 => 'May',
+ 6 => 'June',
+ 7 => 'July',
+ 8 => 'August',
+ 9 => 'September',
+ 10 => 'October',
+ 11 => 'November',
+ 12 => 'December',
+ };
+ }
}
diff --git a/inc/blocks/_setup.php b/inc/blocks/_setup.php
index 3ad061c..091429f 100644
--- a/inc/blocks/_setup.php
+++ b/inc/blocks/_setup.php
@@ -64,6 +64,11 @@
]
);
+ if (!empty(Registrar::withFeature('is_calendar'))) {
+ require('EventBlock.php');
+ new JVBase\blocks\EventBlock();
+ }
+
}
diff --git a/inc/integrations/SyncHelpers.php b/inc/integrations/SyncHelpers.php
index 8cdaf59..84f5303 100644
--- a/inc/integrations/SyncHelpers.php
+++ b/inc/integrations/SyncHelpers.php
@@ -24,6 +24,8 @@
protected static string $syncCustomer;
protected static string $import;
+ protected static array $syncing = ['posts' => [], 'users' => [], 'terms' => []];
+
protected function setQueueTypes():void
{
diff --git a/inc/integrations/SyncToPost.php b/inc/integrations/SyncToPost.php
index 281db8c..d30867d 100644
--- a/inc/integrations/SyncToPost.php
+++ b/inc/integrations/SyncToPost.php
@@ -13,7 +13,6 @@
trait SyncToPost
{
use SyncTo, SyncHelpers, UserConnection;
-
public function addSavePost():void
{
if (!has_action('save_post', [$this, 'handleSavePost'])) {
@@ -28,6 +27,8 @@
{
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
if (wp_is_post_revision($postID) || wp_is_post_autosave($postID)) return;
+ if (isset(self::$syncing['posts'][$postID])) return;
+ self::$syncing['posts'][$postID] = true;
error_log('=== ['.$this->service_name.']::handleSavePost called');
@@ -70,6 +71,7 @@
$this->removeSavePost();
$this->handleTheSavePost($postID, $post, $update, $settings);
$this->addSavePost();
+ unset(self::$syncing['posts'][$postID]);
}
/**
* Handle post save for syncing
diff --git a/inc/integrations/SyncToTerm.php b/inc/integrations/SyncToTerm.php
index 7b2ea09..2056579 100644
--- a/inc/integrations/SyncToTerm.php
+++ b/inc/integrations/SyncToTerm.php
@@ -30,6 +30,9 @@
}
protected function handleSaveTerm(int $termID, int $tt_id, string $taxonomy, bool $update, array $args):void
{
+ if (isset(self::$syncing['terms'][$termID])) {
+ return;
+ }
$tax = jvbNoBase($taxonomy);
if (!in_array($tax, $this->syncTaxonomies)) {
return;
@@ -54,9 +57,11 @@
if ($isShared && $update && !$fields['_keep_synced_'.$this->service_name]) {
return;
}
+ self::$syncing['terms'][$termID] = true;
$this->removeSaveTerm();
$this->handleTheSaveTerm($termID, $update, $taxonomy, $settings);
$this->addSaveTerm();
+ unset(self::$syncing['terms'][$termID]);
}
/**
diff --git a/inc/integrations/SyncToUser.php b/inc/integrations/SyncToUser.php
index 3e0777c..ea8a0ec 100644
--- a/inc/integrations/SyncToUser.php
+++ b/inc/integrations/SyncToUser.php
@@ -36,6 +36,9 @@
}
protected function handleUpdateUser(int $userID):void
{
+ if (isset(self::$syncing['users'][$userID])) {
+ return;
+ }
$user = $this->getOrCreateUser($userID);
if (!$user) {
return;
@@ -45,10 +48,12 @@
if (!empty($fields["_{$this->service_name}_item_id"])) {
return;
}
+ self::$syncing['users'][$userID] = true;
$this->removeSaveUser();
$this->handleTheSaveUser($userID);
$this->addSaveUser();
+ unset(self::$syncing['users'][$userID]);
}
protected function getOrCreateUser(int $userID):string|false
diff --git a/inc/integrations/services/Cloudflare.php b/inc/integrations/services/Cloudflare.php
index 4f1a98b..b8b9278 100644
--- a/inc/integrations/services/Cloudflare.php
+++ b/inc/integrations/services/Cloudflare.php
@@ -49,6 +49,9 @@
protected function initialize(): void
{
// TODO: Implement initialize() method.
+ add_action('woocommerce_review_order_before_submit', [$this, 'addToCheckout']);
+ add_action('wp_enqueue_scripts', [$this, 'enqueueOnCheckout']);
+ add_action('woocommerce_checkout_process', [$this, 'checkoutTurnstile']);
}
public function getServiceDescription():string
@@ -188,4 +191,23 @@
}
return $result['success'] ?? false;
}
+
+ public function enqueueOnCheckout():void
+ {
+ if (function_exists('is_checkout') && is_checkout()) {
+ self::enqueueTurnstileScripts();
+ }
+ }
+ public function addToCheckout():void
+ {
+ self::renderTurnstile();
+ }
+ public function checkoutTurnstile():void
+ {
+ $verified = $this->verifyTurnstile();
+ if (!$verified && function_exists('wc_add_notice')) {
+ wc_add_notice('Security check failed. Please try again', 'error');
+ return;
+ }
+ }
}
diff --git a/inc/managers/DirectoryManager.php b/inc/managers/DirectoryManager.php
index 4f46e0f..4f4b009 100644
--- a/inc/managers/DirectoryManager.php
+++ b/inc/managers/DirectoryManager.php
@@ -37,8 +37,8 @@
jvb_register_do_once('buildDirectories', [$this, 'activate']);
add_action('init', [$this, 'registerDirectories']);
add_filter('pre_render_block', [$this, 'renderBlock'], 20, 3);
- add_action('save_post', [$this, 'flushCache']);
- add_action('edit_terms', [$this, 'flushCache']);
+ add_action('save_post', [$this, 'flushPostCache']);
+ add_action('edit_terms', [$this, 'flushPostCache']);
}
public function flushPostCache(int $postID):void
diff --git a/inc/meta/Meta.php b/inc/meta/Meta.php
index a9412c5..47264d9 100644
--- a/inc/meta/Meta.php
+++ b/inc/meta/Meta.php
@@ -86,6 +86,9 @@
'user' => get_user_meta($this->ID),
default => []
};
+
+ $this->fields = array_map(fn($values) => is_array($values) ? $values[0] : $values, $this->fields);
+
$this->fields = array_combine(
array_map('jvbNoBase', array_keys($this->fields)),
$this->fields
diff --git a/inc/meta/Sanitizer.php b/inc/meta/Sanitizer.php
index fa71881..03b6e39 100644
--- a/inc/meta/Sanitizer.php
+++ b/inc/meta/Sanitizer.php
@@ -14,13 +14,18 @@
public static function sanitize(mixed $value, array $field_config): mixed
{
$callback = static::getCallback($field_config);
+
+// $caller = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3);
+// error_log('Called from: '.print_r($caller, true));
+// $name = $field_config['name']??'';
+//
+// error_log('Sanitizing '.$name. ' with value: '.print_r($value, true));
+
if (is_array($callback)) {
return call_user_func([static::class, $callback[1]], $value, $field_config);
- }
- if (method_exists(static::class, $callback)) {
+ } elseif (method_exists(static::class, $callback)) {
return static::$callback($value, $field_config);
}
-
return call_user_func($callback, $value);
}
@@ -236,25 +241,30 @@
return implode(',', array_intersect($value, array_keys($field_config['options'])));
}
- protected static function sanitizeDate(string $value, array $field_config):string
- {
- $timestamp = strtotime($value);
- return $timestamp ? date('Y-m-d', $timestamp) : '';
- }
-
- protected static function sanitizeDateTime(string $value, array $field_config): string
+ protected static function sanitizeDate(?string $value, array $field_config): string
{
if (empty($value)) {
return '';
}
-
- $timestamp = strtotime($value);
- if (!$timestamp) {
+ try {
+ $date = new \DateTime($value, wp_timezone());
+ } catch (\Exception $e) {
return '';
}
+ return $date->format('Y-m-d');
+ }
- // Return in MySQL datetime format
- return date('Y-m-d H:i:s', $timestamp);
+ protected static function sanitizeDateTime(?string $value, array $field_config): string
+ {
+ if (empty($value)) {
+ return '';
+ }
+ try {
+ $date = new \DateTime($value, wp_timezone());
+ } catch (\Exception $e) {
+ return '';
+ }
+ return $date->format('Y-m-d H:i:s');
}
protected static function sanitizeTime(string $value, array $field_config):string
diff --git a/inc/registrar/Fields.php b/inc/registrar/Fields.php
index d48c56e..71e118b 100644
--- a/inc/registrar/Fields.php
+++ b/inc/registrar/Fields.php
@@ -437,37 +437,37 @@
$business->setHasOfferCatalogField($this);
}
- public function registerPostFields():void
- {
- $postType = $this->registrar->getBased();
- add_meta_box(
- $postType.'_fields',
- 'Extra Fields',
- [$this, 'renderMyMetaBox'],
- $postType,
- 'side',
- 'high'
- );
- }
- public function renderMyMetaBox():void
- {
- $ID = get_the_ID();
- $meta = match ($this->type) {
- 'post' => Meta::forPost($ID),
- 'term' => Meta::forTerm($ID),
- 'user' => Meta::forUser($ID),
- };
- $defaults = array_keys(match($this->type) {
- 'post' => $this->defaultPostFields(),
- 'term' => $this->defaultTermFields(),
- 'user' => $this->defaultUserFields()
- });
- foreach ($this->fields as $fName => $field){
- if (!in_array($fName, $defaults)){
- echo Form::render($fName, $meta->get($fName),$field->getConfig());
- }
- }
- }
+// public function registerPostFields():void
+// {
+// $postType = $this->registrar->getBased();
+// add_meta_box(
+// $postType.'_fields',
+// 'Extra Fields',
+// [$this, 'renderMyMetaBox'],
+// $postType,
+// 'side',
+// 'high'
+// );
+// }
+// public function renderMyMetaBox():void
+// {
+// $ID = get_the_ID();
+// $meta = match ($this->type) {
+// 'post' => Meta::forPost($ID),
+// 'term' => Meta::forTerm($ID),
+// 'user' => Meta::forUser($ID),
+// };
+// $defaults = array_keys(match($this->type) {
+// 'post' => $this->defaultPostFields(),
+// 'term' => $this->defaultTermFields(),
+// 'user' => $this->defaultUserFields()
+// });
+// foreach ($this->fields as $fName => $field){
+// if (!in_array($fName, $defaults)){
+// echo Form::render($fName, $meta->get($fName),$field->getConfig());
+// }
+// }
+// }
public static function getUserFields():array
{
diff --git a/inc/registrar/Registrar.php b/inc/registrar/Registrar.php
index 7b6e7ab..69a4622 100644
--- a/inc/registrar/Registrar.php
+++ b/inc/registrar/Registrar.php
@@ -238,6 +238,9 @@
private static array $instances = [];
protected string $based;
+
+
+ protected static array $processing = ['terms'=>[],'posts'=>[],'users' =>[]];
private function __construct(string $slug, string $singular, string $plural, string $type) {
$this->slug = $slug;
$this->based = jvbCheckBase($slug);
@@ -1060,14 +1063,12 @@
}
public function addTermUpdatedMeta(int $termId):void
{
-
- static $processing = [];
- if (isset($processing[$termId])) return;
- $processing[$termId] = true;
+ if (self::$processing['terms'][$termId]) return;
+ self::$processing['terms'][$termId] = true;
update_term_meta($termId, BASE . 'date_modified', date('Y-m-d H:i:s'));
- unset($processing[$termId]);
+ unset(self::$processing['terms'][$termId]);
}
public function renderContent(string $content, array $block):string
diff --git a/inc/registrar/helpers/AddCustomFields.php b/inc/registrar/helpers/AddCustomFields.php
index 87be897..2be7fd2 100644
--- a/inc/registrar/helpers/AddCustomFields.php
+++ b/inc/registrar/helpers/AddCustomFields.php
@@ -23,7 +23,7 @@
{
switch ($this->registrar->getType()) {
case 'post':
- add_action('save_post', [$this, 'checkPostFields']);
+ add_action('save_post', [$this, 'checkPostFields'], 10, 2);
add_action('enqueue_block_editor_assets', [$this, 'enqueue']);
break;
case 'term':
@@ -92,11 +92,13 @@
? $this->determineSchema($config)
: true;
- $schema = is_array($rawSchema) ? $this->schema($rawSchema) : $rawSchema;
//Allow for null
if ($metaType === 'object') {
- $metaType = ['object', 'null'];
+ $rawSchema['type'] = ['object', 'null'];
}
+
+ $schema = is_array($rawSchema) ? $this->schema($rawSchema) : $rawSchema;
+
register_post_meta($this->registrar->getBased(), jvbCheckBase($name), [
'single' => true,
'type' => $metaType,
@@ -104,7 +106,6 @@
'sanitize_callback' => fn($value) => (Sanitizer::sanitize($value, $config)),
'auth_callback' => fn($allowed, $key, $postID) => current_user_can('edit_post', $postID),
'show_in_rest' => $schema,
- 'revisions_enabled' => true,
]);
}
}
diff --git a/inc/registrar/helpers/MakeCalendarType.php b/inc/registrar/helpers/MakeCalendarType.php
index 53909e9..8425ed1 100644
--- a/inc/registrar/helpers/MakeCalendarType.php
+++ b/inc/registrar/helpers/MakeCalendarType.php
@@ -1,6 +1,7 @@
<?php
namespace JVBase\registrar\helpers;
+use DateTime;
use JVBase\meta\Meta;
use JVBase\registrar\Registrar;
use WP_Post;
@@ -82,17 +83,20 @@
'hidden' => true,
],
'year' => [
- 'type' => 'number',
+ 'type' => 'text',
+ 'subtype' => 'number',
'label' => 'Year',
'hidden' => true,
],
'month' => [
- 'type' => 'number',
+ 'type' => 'text',
+ 'subtype' => 'number',
'label' => 'Month',
'hidden' => true,
],
'day' => [
- 'type' => 'number',
+ 'type' => 'text',
+ 'subtype' => 'number',
'label' => 'Day',
'hidden' => true,
],
@@ -129,6 +133,7 @@
'max_participants' => [
'type' => 'number',
'label' => 'Maximum Participants',
+ 'hint' => 'Leave 0 for no maximum'
],
'is_free' => [
'type' => 'true_false',
@@ -311,6 +316,23 @@
if ($post->post_type === $this->postType) {
$get = ['year', 'month','day'];
$values = Meta::forPost($post->ID)->getAll($get);
+
+ if (empty($values['year']) || empty($values['month']) || empty($values['day'])) {
+ $value = Meta::forPost($post->ID)->get('date_start');
+ if (!empty($value)) {
+ $date = new DateTime($value, wp_timezone());
+ $year = $date->format('Y');
+ $month = $date->format('m');
+ $day = $date->format('d');
+
+ $values = [
+ 'year' => $year,
+ 'month' => $month,
+ 'day' => $day
+ ];
+ Meta::forPost($post->ID)->setAll($values);
+ }
+ }
foreach ($values as $key => $value) {
if (!empty($value) && $value !== 0) {
$url = str_replace("%e$key%", $value, $url);
diff --git a/jvb.php b/jvb.php
index 8f1544b..078d964 100644
--- a/jvb.php
+++ b/jvb.php
@@ -442,7 +442,7 @@
{
NewsRoutes::getInstance();
}
-
+
OpenStreetMaps::getInstance();
}
@@ -563,3 +563,4 @@
{
return Registrar::maybeExcludeSingles($IDs);
}
+
diff --git a/src/_meta/fields/date-field.js b/src/_meta/fields/date-field.js
index 73a4cd7..d87e962 100644
--- a/src/_meta/fields/date-field.js
+++ b/src/_meta/fields/date-field.js
@@ -1,8 +1,8 @@
-import { useState } from 'react';
import { DatePicker } from '@wordpress/components';
const DateField = ({field, value, onChange}) => {
// const [ date, setDate ] = useState( new Date() );
+
return (
<div className="components-base-control" id={field.name}>
<label className="components-base-control__label">
@@ -21,6 +21,7 @@
const toLocalDate = (value) => {
if (!value) return null;
const [year, month, day] = value.split('-').map(Number);
+ if (!year || !month || !day) return null;
return new Date(year, month - 1, day);
};
diff --git a/src/_meta/fields/datetime-field.js b/src/_meta/fields/datetime-field.js
index f3d966f..41d0e43 100644
--- a/src/_meta/fields/datetime-field.js
+++ b/src/_meta/fields/datetime-field.js
@@ -2,7 +2,6 @@
import { DateTimePicker } from '@wordpress/components';
const DateTimeField = ({field, value, onChange}) => {
- const [ date, setDate ] = useState( new Date() );
return (
@@ -11,9 +10,8 @@
{ field.label }
</label>
<DateTimePicker
- currentDate={ date }
+ currentDate={ value||null }
onChange={ onChange }
- label={ field.label }
help={ field.description }
value={value??''}
is12Hour={ true }
diff --git a/src/_meta/fields/selector-field.js b/src/_meta/fields/selector-field.js
index 7c18a05..5707ea5 100644
--- a/src/_meta/fields/selector-field.js
+++ b/src/_meta/fields/selector-field.js
@@ -18,7 +18,7 @@
};
const createPayload = (field, subtype, name) =>
- subtype === 'post' ? { title: name, status: 'publish', postType: field.post_type } : { name };
+ subtype === 'post' ? { title: name, status: 'publish', postType: field.post_type } : { name: name };
const labelOf = (item, subtype) => (subtype === 'user' ? item.name : item.title?.rendered ?? item.title ?? item.name);
@@ -90,7 +90,7 @@
if (pendingCreate && canCreate && !creating) {
setCreating(true);
- apiFetch({ path: `/wp/v2/${field.taxonomy}`, method: 'POST', data: createPayload(subtype, search) })
+ apiFetch({ path: `/wp/v2/${field.taxonomy}`, method: 'POST', data: createPayload(field, subtype, search) })
.then((item) => {
const label = labelOf(item, subtype);
const finalTokens = tokens.filter((t) => t !== createLabel).concat(label);
diff --git a/src/_meta/fields/upload-field.js b/src/_meta/fields/upload-field.js
index edb5939..7da36a8 100644
--- a/src/_meta/fields/upload-field.js
+++ b/src/_meta/fields/upload-field.js
@@ -39,13 +39,16 @@
const UploadField = ({ field, value, onChange }) => {
const multiple = field.multiple || field.type === 'gallery';
- const ids = multiple ? (Array.isArray(value) ? value : []) : value;
+ const ids = multiple
+ ? (typeof value === 'string' && value ? value.split(',').map(Number) : [])
+ : value;
const allowedTypes = SUBTYPE_MAP[field.subtype] ? [SUBTYPE_MAP[field.subtype]] : '';
- const onSelect = (media) => onChange(multiple ? media.map((m) => m.id) : media.id);
+ const onSelect = (media) =>
+ onChange(multiple ? media.map((m) => m.id).join(',') : media.id);
const onRemove = (id) => {
- onChange(multiple ? ids.filter((existing) => existing !== id) : 0);
+ onChange(multiple ? ids.filter((existing) => existing !== id).join(',') : 0);
};
return (
diff --git a/src/event/block.json b/src/event/block.json
new file mode 100644
index 0000000..c06ea44
--- /dev/null
+++ b/src/event/block.json
@@ -0,0 +1,24 @@
+{
+ "$schema": "https://schemas.wp.org/trunk/block.json",
+ "apiVersion": 3,
+ "name": "jvb/event",
+ "title": "Event Summary",
+ "category": "jvb",
+ "icon": "align-center",
+ "description": "Outputs the event information",
+ "keywords": [ "event" ],
+ "version": "0.9.0",
+ "textdomain": "jvb",
+ "supports": {
+ "html": false,
+ "align": ["wide", "full"]
+ },
+ "selectors": {
+ "root": ".event-block"
+ },
+ "render": "file:./render.php",
+ "editorScript": "file:./index.js",
+ "editorStyle": "file:./index.css",
+ "style": "file:./style-index.css",
+ "viewScript": "file:./view.js"
+}
diff --git a/src/event/edit.js b/src/event/edit.js
new file mode 100644
index 0000000..3528965
--- /dev/null
+++ b/src/event/edit.js
@@ -0,0 +1,29 @@
+/**
+ * WordPress dependencies
+ */
+import { __ } from '@wordpress/i18n';
+import { useBlockProps, InspectorControls } from '@wordpress/block-editor';
+import { SelectControl, ToggleControl, PanelBody } from '@wordpress/components';
+
+/**
+ * Styles
+ */
+import './editor.scss';
+
+/**
+ * Edit function for Summary Block
+ */
+export default function Edit({ attributes, setAttributes }) {
+ const blockProps = useBlockProps();
+
+ return (
+ <div {...blockProps}>
+ <div className="jvb-summary-preview">
+ <h3>{__('Summary', 'jvb')}</h3>
+ <p className="jvb-list-preview-note">
+ {__('This will inherit the current query to build the information from our custom meta on the front end.', 'jvb')}
+ </p>
+ </div>
+ </div>
+ );
+}
diff --git a/src/event/editor.scss b/src/event/editor.scss
new file mode 100644
index 0000000..59e1f42
--- /dev/null
+++ b/src/event/editor.scss
@@ -0,0 +1,20 @@
+/**
+ * Directory List Block Editor Styles
+ */
+.jvb-summary-preview {
+ padding: 20px;
+ background-color: #f8f9fa;
+ border: 1px solid #e2e4e7;
+ border-radius: 4px;
+
+ h3 {
+ margin-top: 0;
+ padding-bottom: 10px;
+ border-bottom: 1px solid #ff0080;
+ }
+ &-note {
+ font-style: italic;
+ color: #555d66;
+ margin-bottom: 0;
+ }
+}
diff --git a/src/event/index.js b/src/event/index.js
new file mode 100644
index 0000000..980b9a8
--- /dev/null
+++ b/src/event/index.js
@@ -0,0 +1,39 @@
+/**
+ * Registers a new block provided a unique name and an object defining its behavior.
+ *
+ * @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/
+ */
+import { registerBlockType } from '@wordpress/blocks';
+
+/**
+ * Lets webpack process CSS, SASS or SCSS files referenced in JavaScript files.
+ * All files containing `style` keyword are bundled together. The code used
+ * gets applied both to the front of your site and to the editor.
+ *
+ * @see https://www.npmjs.com/package/@wordpress/scripts#using-css
+ */
+import './style.scss';
+
+/**
+ * Internal dependencies
+ */
+import Edit from './edit';
+import save from './save';
+import metadata from './block.json';
+
+/**
+ * Every block starts by registering a new block type definition.
+ *
+ * @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/
+ */
+registerBlockType( metadata.name, {
+ /**
+ * @see ./edit.js
+ */
+ edit: Edit,
+
+ /**
+ * @see ./save.js
+ */
+ save,
+} );
diff --git a/src/event/index.php b/src/event/index.php
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/event/index.php
diff --git a/src/event/render.php b/src/event/render.php
new file mode 100644
index 0000000..371cae0
--- /dev/null
+++ b/src/event/render.php
@@ -0,0 +1,5 @@
+<?php
+
+if (!defined('ABSPATH')) {
+ exit; // Exit if accessed directly
+}
diff --git a/src/event/save.js b/src/event/save.js
new file mode 100644
index 0000000..2c31392
--- /dev/null
+++ b/src/event/save.js
@@ -0,0 +1,3 @@
+export default function save() {
+ return null; // Dynamic block rendered by PHP
+}
diff --git a/src/event/style.scss b/src/event/style.scss
new file mode 100644
index 0000000..8319146
--- /dev/null
+++ b/src/event/style.scss
@@ -0,0 +1,60 @@
+.event-block {
+
+ .tags {
+ --gap: 1rem;
+
+ .tag {
+ display: flex;
+ gap: .5rem;
+ background-color: rgb(var(--action-0));
+ color: rgb(var(--action-contrast));
+ font-size: var(--txt-x-small);
+ text-transform: uppercase;
+ border-radius: 4px;
+ padding: .25rem .5rem 0;
+ }
+ }
+
+ header {
+ --wrap: nowrap!important;
+ gap: 1rem;
+
+ h1 {
+ margin: 0;
+ }
+ }
+
+ .calendar.col {
+ border-radius: .5rem;
+ border: 2px solid rgb(var(--action-0));
+ width: var(--btn_);
+ --align: stretch;
+ --gap: 0;
+
+ span {
+ text-align: center;
+ text-transform: uppercase;
+ line-height: .8;
+ }
+ .weekday {
+ background-color: rgb(var(--action-0));
+ color: rgb(var(--action-contrast));
+ font-weight: var(--fw-h-bold);
+ font-family: var(--heading);
+ line-height: 1.4;
+ margin-bottom: .5rem;
+ }
+
+ .day {
+ font-size: var(--txt-xx-large);
+ }
+ }
+ .gallery figure {
+ max-width: min(15vw, 8rem) !important;
+ aspect-ratio: 1;
+ object-fit: cover;
+ }
+ figcaption {
+ display: none;
+ }
+}
diff --git a/src/event/view.js b/src/event/view.js
new file mode 100644
index 0000000..d3f5a12
--- /dev/null
+++ b/src/event/view.js
@@ -0,0 +1 @@
+
diff --git a/src/simple-calendar/style.scss b/src/simple-calendar/style.scss
index 90bdd10..6b0cfac 100644
--- a/src/simple-calendar/style.scss
+++ b/src/simple-calendar/style.scss
@@ -12,3 +12,12 @@
margin: 0;
}
}
+
+
+
+.simple-calendar {
+
+ nav.calendar.types {
+ height: max-content;
+ }
+}
--
Gitblit v1.10.0