Plugin Directory

Changeset 3458296


Ignore:
Timestamp:
02/10/2026 05:33:50 PM (7 weeks ago)
Author:
trainingbusinesspros
Message:

Update to version 4.2.12 from GitHub

Location:
groundhogg
Files:
30 added
26 edited
1 copied

Legend:

Unmodified
Added
Removed
  • groundhogg/tags/4.2.12/README.txt

    r3442828 r3458296  
    77Tested up to: 6.9
    88Requires PHP: 7.1
    9 Stable tag: 4.2.10
     9Stable tag: 4.2.12
    1010License: GPLv3
    1111License URI: https://www.gnu.org/licenses/gpl.md
     
    378378
    379379== Changelog ==
     380
     381= 4.2.12 (2026-02-10) =
     382* ADDED Bluesky social icons for the email editor.
     383* ADDED Bulk delete bulk action for campaigns.
     384* FIXED Email preview link stopped working in the emails table.
     385* FIXED Notice generated by improper array access check when submitting a form.
    380386
    381387= 4.2.11 (2026-01-19) =
  • groundhogg/tags/4.2.12/admin/broadcasts/broadcasts-table.php

    r3400645 r3458296  
    245245
    246246        if ( $broadcast->is_email() ){
    247             $actions[] = html()->a( '#', esc_html__( 'Preview', 'groundhogg' ), [ 'class' => 'gh-email-preview', 'data-id' => $broadcast->get_object_id() ] );
     247            $actions[] = html()->a( '#gh-email-preview/' . $broadcast->get_object_id(), esc_html__( 'Preview', 'groundhogg' ) );
    248248        }
    249249
  • groundhogg/tags/4.2.12/admin/campaigns/campaigns-table.php

    r3343709 r3458296  
    4747        // Set parent defaults.
    4848        parent::__construct( array(
    49             'singular' => 'tag',     // Singular name of the listed records.
    50             'plural'   => 'tags',    // Plural name of the listed records.
     49            'singular' => 'campaign',     // Singular name of the listed records.
     50            'plural'   => 'campaigns',    // Plural name of the listed records.
    5151            'ajax'     => false,       // Does this table support ajax?
    5252        ) );
     53    }
     54
     55    /**
     56     * @return array An associative array containing all the bulk actions.
     57     */
     58    protected function get_bulk_actions() {
     59
     60        $actions = array(
     61            'delete' => _x( 'Delete', 'List table bulk action', 'groundhogg' ),
     62        );
     63
     64        return apply_filters( 'groundhogg/admin/campaigns/table/bulk_actions', $actions );
    5365    }
    5466
  • groundhogg/tags/4.2.12/admin/emails/emails-table.php

    r3400645 r3458296  
    331331            default:
    332332                $actions[] = [ 'class' => 'edit', 'display' => esc_html__( 'Edit' , 'groundhogg' ), 'url' => $item->admin_link() ];
    333                 $actions[] = [ 'class' => 'gh-email-preview', 'display' => esc_html__( 'Preview' , 'groundhogg' ), 'url' => '#' ];
     333                $actions[] = [ 'class' => 'gh-email-preview', 'display' => esc_html__( 'Preview' , 'groundhogg' ), 'url' => '#gh-email-preview/' . $item->get_id() ];
    334334                $actions[] = [
    335335                    'class'   => 'duplicate',
  • groundhogg/tags/4.2.12/admin/reports/views/broadcast-single.php

    r3400645 r3458296  
    1717    <h1 class="report-title"><?php echo esc_html( $broadcast->get_title() ) ?></h1>
    1818    <?php if ( $broadcast->is_email() ): ?>
    19         <a href="#" class="gh-button secondary gh-email-preview" data-id="<?php echo esc_attr( $broadcast->get_object_id() ); ?>"><?php esc_html_e( 'Preview', 'groundhogg' ); ?></a>
     19        <a href="#gh-email-preview/<?php echo esc_attr( $broadcast->get_object_id() ); ?>" class="gh-button secondary"><?php esc_html_e( 'Preview', 'groundhogg' ); ?></a>
    2020    <?php endif; ?>
    2121</div>
  • groundhogg/tags/4.2.12/assets/js/admin/components.js

    r3422142 r3458296  
    17961796      EmailPreviewModal(parseInt(emailId), {})
    17971797    })
     1798
     1799    window.addEventListener('hashchange', e => {
     1800      let hash = window.location.hash.replace('#', '')
     1801      if ( hash.startsWith('gh-email-preview/') ) {
     1802        let emailId = hash.replace('gh-email-preview/', '')
     1803        EmailPreviewModal(parseInt(emailId), {})
     1804      }
     1805    })
    17981806  })
    17991807
  • groundhogg/tags/4.2.12/assets/js/admin/components.min.js

    r3422142 r3458296  
    216216      <div id="uploading-files"></div>
    217217      <div id="uploaded-files"></div>
    218       `,onOpen:({close})=>{let file=null;let filesToUpload=[];let filesUploaded=[];let uploading=false;const pushFiles=()=>{renderUploadingFiles();file=filesToUpload.pop();if(!file){uploading=false;return}uploading=true;let fd=new FormData;fd.append(fileName,file,file.name);fd.append("gh_admin_ajax_nonce",Groundhogg.nonces._adminajax);fd.append("action",action);beforeUpload(fd);setTimeout(()=>{fetch(ajaxurl,{method:"POST",credentials:"same-origin",body:fd}).then(r=>{if(!r.ok){dialog({message:__("Something when wrong..."),type:"error"});return}return r.json()}).then(r=>{if(!r.success){dialog({message:r.data[0].message,type:"error"});pushFiles();return}onUpload(r,file);filesUploaded.unshift(file);renderUploadedFiles();pushFiles()})},2e3)};const renderUploadingFiles=()=>{$("#uploading-files").html(filesToUpload.map(f=>`<div class="file"><span class="hourglass">⌛</span> ${f.name}</div>`))};const renderUploadedFiles=()=>{$("#uploaded-files").html(filesUploaded.map(f=>`<div class="file">✅ ${f.name}</div>`))};const addFiles=files=>{filesToUpload.push(...files);if(!uploading){pushFiles()}};const $input=$("#upload-file-input");$input.on("change",e=>{addFiles(e.target.files)});$("#select-files").on("click",e=>{e.preventDefault();$input.click()});const $droppable=$(".droppable-handler");$droppable.on("dragover",e=>{e.preventDefault();$droppable.addClass("dragover")}).on("dragleave",e=>{$droppable.removeClass("dragover")}).on("drop",e=>{e.preventDefault();$droppable.removeClass("dragover");let{dataTransfer}=e.originalEvent;addFiles(dataTransfer.files)})}})};const EmailPreviewModal=async(emailId,{height=window.innerHeight*.85,width=900})=>{const{close}=loadingModal();let email;try{email=await EmailsStore.maybeFetchItem(emailId)}catch(err){close();throw err}const{from_avatar,from_email,from_name,subject,built:content}=email.context;close();return ModalFrame({frameAttributes:{className:"gh-modal-frame gh-email-preview-modal"}},({close})=>Div({style:{width:`${width}px`,height:`${height}px`}},EmailPreview({close:close,from_avatar:from_avatar,from_email:from_email,from_name:from_name,subject:subject,content:content})))};const EmailPreview=({close=false,from_avatar,from_email,from_name,subject,content})=>{return Div({className:"email-preview"},[Div({className:"from-preview display-flex gap-20 has-box-shadow"},[makeEl("img",{src:from_avatar,className:"from-avatar",height:40,width:40,style:{borderRadius:"50%"}}),Div({className:"subject-and-from"},[`<h2>${subject}</h2>`,`<span class="from-name">${from_name}</span> <span class="from-email">&lt;${from_email}&gt;</span>`]),close!==false?Button({className:"gh-button secondary icon text",style:{marginLeft:"auto"},onClick:close},Dashicon("no-alt")):null]),Iframe({id:"desktop-preview-iframe"},content)])};$(()=>{$(document).on("click","a.gh-email-preview",e=>{e.preventDefault();let emailId=e.currentTarget.dataset.id??e.currentTarget.closest("tr").id;EmailPreviewModal(parseInt(emailId),{})})});const ImagePicker=({multiple=false,title=__("Select a image to upload"),selectText=__("Use this image"),onChange=attachment=>{}})=>{let file_frame=wp.media({title:title,button:{text:selectText},multiple:multiple});file_frame.on("select",function(){let attachment=file_frame.state().get("selection").first().toJSON();onChange(attachment)});file_frame.open()};const ImageInput=({id,name="src",onChange,value=""})=>{const handleChange=(value,attachment=null)=>{onChange(value,attachment);morphdom(document.getElementById(id),ImageInput({id:id,name:name,onChange:onChange,value:value}))};return Div({id:id,className:"image-picker"},[value?Div({id:`${id}-preview`,className:"image-input-preview",style:{backgroundImage:`url(${value})`},onClick:e=>{e.preventDefault();ImagePicker({multiple:false,onChange:attachment=>handleChange(attachment.url,attachment)})}}):null,InputGroup([Input({type:"text",id:`${id}-src`,value:value,className:"control full-width",name:name,onChange:e=>{handleChange(e.target.value,null)}}),Button({id:`${id}-select`,className:"gh-button secondary icon",onClick:e=>{e.preventDefault();ImagePicker({multiple:false,onChange:attachment=>handleChange(attachment.url,attachment)})}},icons.image)])])};const FeedbackModal=({subject="",message="",onSubmit=r=>{}})=>{const State=Groundhogg.createState({subject:subject,message:message,submitting:false});ModalWithHeader({width:"400px",header:"Send Feedback"},({close,morph})=>Form({className:"display-flex column gap-5",onSubmit:e=>{e.preventDefault();State.set({submitting:true});morph();Groundhogg.api.ajax({action:"gh_plugin_feedback",subject:State.subject,message:State.message}).then(r=>{onSubmit(r);dialog({message:"Thanks for your feedback!"});close()});return false}},[Label({for:"feedback-subject"},["What feature are you submitting feedback for?"]),Input({id:"feedback-subject",value:State.subject,required:true,onInput:e=>State.set({subject:e.target.value})}),Div(),Label({for:"feedback-message"},["What is your feedback? Be as descriptive as possible."]),Textarea({id:"feedback-message",value:State.message,required:true,rows:4,onInput:e=>State.set({message:e.target.value})}),Button({className:"gh-button primary",type:"submit",disabled:State.submitting},"Send feedback"),Pg({},"Your email address will be collected to validate your feedback, but will not be used beyond that.")]))};$(document).on("click","a.feedback-modal",e=>{e.preventDefault();const{subject="",message=""}=e.currentTarget.dataset;FeedbackModal({subject:subject,message:message})});const ContactPhone=(icon,number,extension="")=>number?Span({className:"contact-phone"},[icon,An({href:`tel:${number}`},number),extension?Span({className:"ext"},` x${extension}`):null]):null;const ContactListItem=(item,{extra=item=>null,...props}={})=>{let allTags=jsonCopy(item.tags);let showTags=allTags.splice(0,10);const{ID}=item;const{full_name,gravatar,date_created,email}=item.data;const{primary_phone="",primary_phone_extension="",mobile_phone="",company_phone="",company_phone_extension=""}=item.meta;return Div({className:`contact-list-item`,id:`contact-list-item-${ID}`,dataId:ID,...props},[Div({className:"display-flex gap-10"},[Img({className:"avatar",src:gravatar,alt:"avatar"}),Div({className:"display-flex column"},[Div({},[makeEl("h4",{style:{margin:0}},full_name),Span({className:"subscribed"},`&nbsp;— ${sprintf(__("Subscribed %s"),`<abbr title="${formatDateTime(date_created)}">${sprintf(__("%s ago "),item.i18n.created)}</abbr>`)}`)]),Div({},[An({href:`mailto:${email}`},email),Span({},[" — ",Span({className:`gh-text ${item.is_marketable?"green":"red"}`},Groundhogg.filters.optin_status[item.data.optin_status])])])])]),Div({className:"show-on-hover"},[primary_phone||company_phone||mobile_phone?Div({className:"contact-phones"},[ContactPhone(icons.mobile,mobile_phone),ContactPhone(icons.phone,primary_phone,primary_phone_extension),ContactPhone(icons.phone,company_phone,company_phone_extension)]):null,Div({className:"gh-tags"},[...showTags.map(tag=>Span({className:"gh-tag"},tag.data.tag_name)),allTags.length?Span({},sprintf("and %d more...",allTags.length)):null]),maybeCall(extra,item)])])};const ContactList=(contacts=[],{noContacts=()=>null,itemProps={}}={})=>{if(!contacts.length){return maybeCall(noContacts)}return Div({className:"contact-list"},contacts.map(contact=>ContactListItem(contact,maybeCall(itemProps,contact))))};const QuickSearch=({itemProps={},queryOverrides={}}={})=>{const State=Groundhogg.createState({search:"",searched:false,results:[],loaded:false});const fetchResults=async()=>{let results=await ContactsStore.fetchItems({search:State.search,orderby:"date_created",order:"DESC",limit:5,...queryOverrides});State.set({results:results,searched:true,loaded:true})};return Div({id:"quick-search-wrap"},morph=>{if(!State.loaded){fetchResults().then(morph)}const updateResults=debounce(async()=>{await fetchResults();morph()},300);return Fragment([Form({action:adminPageURL("gh_contacts")},[Input({type:"hidden",name:"page",value:"gh_contacts"}),Input({id:"quick-search-input",placeholder:__("Search by name or email...","groundhogg"),type:"search",name:"s",value:State.search,onInput:e=>{State.set({search:e.target.value});updateResults()}})]),State.loaded?null:Skeleton({},["full","full","full"]),State.results.length?ContactList(State.results,{itemProps:item=>({className:"contact-list-item clickable",onClick:e=>{window.open(item.admin,"_self")},...maybeCall(itemProps,item)})}):null,State.results.length===0&&State.searched?Pg({style:{textAlign:"center"}},__("No contacts found for the current search","groundhogg")):null])})};const Panel=({id,name,collapsed=false,hidden=false,onCollapse=id=>{}},content)=>{if(hidden){return null}return Div({id:`${id}-panel`,className:`gh-panel ${collapsed?"closed":""}`},[Div({className:`gh-panel-header`},[H2({},name),Button({className:"toggle-indicator",onClick:e=>{onCollapse(id)}})]),collapsed?null:maybeCall(content)])};const Panels=overrides=>({...Groundhogg.createRegistry({}),storagePrefix:"gh-panels",collapse(id){if(!this.isCollapsed(id)){this.toggleCollapse(id)}},expand(id){if(this.isCollapsed(id)){this.toggleCollapse(id)}},hide(id){if(!this.isHidden(id)){this.toggleHidden(id)}},show(id){if(this.isHidden(id)){this.toggleHidden(id)}},togglePanel(id,suffix){let panels=this.getPanelIds(suffix);if(panels.includes(id)){panels.splice(panels.indexOf(id),1)}else{panels.push(id)}localStorage.setItem(`${this.storagePrefix}-${suffix}`,JSON.stringify(panels))},toggleHidden(id){this.togglePanel(id,"hidden")},toggleCollapse(id){this.togglePanel(id,"collapsed")},getPanelIds(suffix){return JSON.parse(localStorage.getItem(`${this.storagePrefix}-${suffix}`))||[]},getHiddenPanelIds(){return this.getPanelIds("hidden")},getCollapsedPanelIds(){return this.getPanelIds("collapsed")},isHidden(id){return this.getHiddenPanelIds().includes(id)},isCollapsed(id){return this.getCollapsedPanelIds().includes(id)},PanelControls(){return Div({},[...this.map((item,id)=>Div({className:"display-flex gap-10",style:{marginBottom:"10px"}},[Toggle({checked:!this.isHidden(id),id:`toggle-${id}`,onChange:e=>{this.toggleHidden(id)}}),Label({for:`toggle-${id}`},item.name)]))])},Panel(id){let{content,...panel}=this.get(id);return Panel({id:id,...panel,collapsed:this.isCollapsed(id),hidden:this.isHidden(id),onCollapse:id=>{this.toggleCollapse(id);morphdom(document.getElementById(`${id}-panel`),this.Panel(id))}},content)},Panels(){return Div({className:"display-flex column gap-20",id:this.storagePrefix},this.keys().map(id=>this.Panel(id)))},...overrides});const Relationships=({title="",id,store,child_type="",parent_type="",renderItem=item=>{},onAddItem=(r,j)=>{}})=>{const rel_type_key=child_type?"child_type":"parent_type";const rel_type=child_type||parent_type;const rel_id_key=child_type?"child_id":"parent_id";const State=Groundhogg.createState({loaded:false,items:[]});const fetchRelationships=()=>store.fetchRelationships(id,{[rel_type_key]:rel_type}).then(items=>State.set({items:items,loaded:true}));const deleteRelationship=itemId=>store.deleteRelationships(id,{[rel_type_key]:rel_type,[rel_id_key]:itemId}).then(()=>State.set({items:State.items.filter(item=>item.ID!==itemId)}));const createRelationship=item=>store.createRelationships(id,{[rel_type_key]:rel_type,[rel_id_key]:item.ID}).then(()=>State.set({items:[...State.items,item]}));return Div({id:`${rel_type_key}-${rel_type}-rel-of-${id}`,className:`display-flex column relationship-editor ${rel_type_key}-${rel_type}`},morph=>{const handleDeleteRelationship=itemId=>deleteRelationship(itemId).then(morph);if(!State.loaded){fetchRelationships().then(morph);return Skeleton({},["full","full","full"])}const AddRelButton=()=>Button({id:`add-${rel_type_key}-${rel_type}-rel-for-${id}`,className:"gh-button secondary text icon",onClick:e=>{let promise=new Promise((resolve,reject)=>onAddItem(resolve,reject,State));promise.then(item=>createRelationship(item).then(morph))}},[Dashicon("plus-alt2"),ToolTip(__("Add relationship","groundhogg"),"left")]);return Fragment([title?Div({className:"space-between"},[H4({},title),AddRelButton()]):null,...State.items.map(item=>renderItem({...item,onDelete:handleDeleteRelationship})),title?null:Div({className:"display-flex flex-end"},AddRelButton())])})};const OwnerPicker=({id="select-owners",selected=[],onChange=ids=>{},allow0=true,itemDisplay=user=>user.data.display_name,multiple=true,...overrides})=>ItemPicker({id:`select-users`,noneSelected:__("Select a user...","groundhogg"),selected:selected.map(user_id=>{if(user_id==0&&allow0){return{id:0,text:__("The contact owner","groundhogg")}}return{id:user_id,text:itemDisplay(getOwner(user_id))}}),multiple:multiple,style:{flexGrow:1},isValidSelection:id=>id===0||getOwner(id),fetchOptions:search=>{search=new RegExp(search,"i");let options=Groundhogg.filters.owners.map(u=>({id:u.ID,text:itemDisplay(u)}));if(allow0){options.push({id:0,text:__("The contact owner","groundhogg")})}options=options.filter(({text})=>text.match(search));return Promise.resolve(options)},onChange:items=>{if(multiple){onChange(items.map(({id})=>id));return}onChange(items)},...overrides});function getClosestRelativeAncestor(element){let parent=element.parentElement;while(parent){if(window.getComputedStyle(parent).position==="relative"){return parent}parent=parent.parentElement}return null}const Tour=(steps,{onFinish=()=>{},beforeDismiss=({dismiss})=>dismiss(),onDismiss=()=>{},fixed=false})=>{const State=Groundhogg.createState({current:0,step:null,target:null,relative:null});const currentStep=()=>steps[State.current];const removeSteps=()=>{document.querySelectorAll(".tour-prompt-container").forEach(el=>el.remove());document.querySelectorAll(".tour-prompt").forEach(el=>el.remove());document.querySelectorAll(".tour-highlighted").forEach(el=>el.classList.remove("tour-highlighted"))};const remove=()=>{removeSteps();document.removeEventListener("resize",rePositionStep);document.removeEventListener("scroll",rePositionStep)};const dismiss=async()=>{remove();onDismiss()};const next=()=>{const{onNext=()=>{}}=currentStep();onNext();if(State.current+1>=steps.length){remove();onFinish(true);return}State.current++;showStep()};const prev=()=>{const{onPrev=()=>{}}=currentStep();onPrev();if(State.current<=0){return}State.current--;showStep()};const showStep=()=>{removeSteps();positionStep()};function rePositionStep(){let{position}=currentStep();let{target,relative,step,windowEl}=State;const targetPos=target.getBoundingClientRect();const relativePos=relative.getBoundingClientRect();const stepPos=step.getBoundingClientRect();const gap=20;if(fixed){windowEl.style.height=`${targetPos.height+gap*2}px`;windowEl.style.width=`${targetPos.width+gap*2}px`;windowEl.style.borderWidth=`${Math.round(targetPos.y)-gap}px ${Math.round(window.innerWidth-targetPos.x)-gap}px ${Math.round(window.innerHeight-targetPos.y)-gap}px ${Math.round(targetPos.x)-gap}px`;switch(position){case"right":step.style.left=`${targetPos.x+targetPos.width+gap}px`;step.style.top=`${targetPos.y}px`;break;case"left":step.style.left=`${targetPos.x-stepPos.width-gap}px`;step.style.top=`${targetPos.y}px`;break;case"above":step.style.left=`${targetPos.x}px`;step.style.top=`${targetPos.y-stepPos.height-gap}px`;break;case"below":step.style.left=`${targetPos.x}px`;step.style.top=`${targetPos.y+targetPos.height+gap}px`;break;case"below-left":step.style.left=`${targetPos.x+targetPos.width-stepPos.width}px`;step.style.top=`${targetPos.y+targetPos.height+gap}px`;break}return}switch(position){case"right":step.style.left=`${targetPos.right-relativePos.left+gap}px`;step.style.top=`${targetPos.top-relativePos.top}px`;break;case"left":step.style.left=`${targetPos.left-relativePos.left-stepPos.width-gap}px`;step.style.top=`${targetPos.top-relativePos.top}px`;break;case"above":step.style.left=`${targetPos.left-relativePos.left}px`;step.style.top=`${targetPos.top-relativePos.top-stepPos.height-gap}px`;break;case"below":step.style.left=`${targetPos.left-relativePos.left}px`;step.style.top=`${targetPos.bottom-relativePos.top+gap}px`;break;case"below-left":step.style.left=`${targetPos.right-relativePos.left-stepPos.width}px`;step.style.top=`${targetPos.bottom-relativePos.top+gap}px`;break}}function positionStep(){let tourEl=TourStep();let windowEl=tourEl.querySelector(".tour-window");let stepEl=tourEl.querySelector(".tour-prompt");let{target,relative,onInit=()=>{},onBefore=()=>{}}=currentStep();target=document.querySelector(target);if(!target){next();return}if(fixed){relative=document.body}else if(relative){relative=target.closest(relative)}else{relative=getClosestRelativeAncestor(target)}stepEl.style.position=fixed?"fixed":"absolute";if(fixed){relative.append(tourEl)}else{target.classList.add("tour-highlighted");relative.append(stepEl)}target.scrollIntoView({behavior:"instant",block:"center",inline:"center"});onBefore({next:next,prev:prev,target:target,relative:relative,step:stepEl,windowEl:windowEl,currentStep:currentStep});State.set({step:stepEl,windowEl:windowEl,target:target,relative:relative});rePositionStep();onInit({next:next,prev:prev,target:target,relative:relative,step:stepEl,windowEl:windowEl,currentStep:currentStep});stepEl.querySelector("#tour-next").focus()}const TourStep=()=>MakeEl.Div({className:"tour-prompt-container"},[fixed?MakeEl.Div({className:"tour-window"},[MakeEl.Div({className:"tour-window-shadow",onClick:next})]):null,MakeEl.Div({className:`tour-prompt ${currentStep().position}`,style:{padding:"10px",width:"200px"}},[MakeEl.Button({className:"dismiss",onClick:e=>{beforeDismiss({dismiss:dismiss,State:State})}},MakeEl.Dashicon("no-alt")),MakeEl.Div({},currentStep().prompt),MakeEl.Div({className:"display-flex flex-end gap-5 space-above-10"},[State.current>0?MakeEl.Button({id:"tour-prev",className:"gh-button small secondary text prev-step",onClick:()=>prev()},"Prev"):null,currentStep().showNext===false?null:MakeEl.Button({id:"tour-next",className:`gh-button small ${State.current<steps.length-1?"secondary":"primary"} next-step`,onClick:()=>next()},State.current<steps.length-1?"Next":"Finish")])])]);document.addEventListener("resize",rePositionStep);document.addEventListener("scroll",rePositionStep);positionStep()};Groundhogg.components={QuickSearch:QuickSearch,addContactModal:addContactModal,internalForm:internalForm,betterTagPicker:betterTagPicker,quickAddForm:quickAddForm,selectContactModal:selectContactModal,quickEditContactModal:quickEditContactModal,makeInput:makeInput,emailModal:emailModal,EmailTemplateModal:EmailTemplateModal,fileUploader:fileUploader,EmailPreview:EmailPreview,EmailPreviewModal:EmailPreviewModal,ImageInput:ImageInput,ImagePicker:ImagePicker,FeedbackModal:FeedbackModal,ContactList:ContactList,ContactListItem:ContactListItem,Panel:Panel,Panels:Panels,Relationships:Relationships,OwnerPicker:OwnerPicker,Tour:Tour}})(jQuery);
     218      `,onOpen:({close})=>{let file=null;let filesToUpload=[];let filesUploaded=[];let uploading=false;const pushFiles=()=>{renderUploadingFiles();file=filesToUpload.pop();if(!file){uploading=false;return}uploading=true;let fd=new FormData;fd.append(fileName,file,file.name);fd.append("gh_admin_ajax_nonce",Groundhogg.nonces._adminajax);fd.append("action",action);beforeUpload(fd);setTimeout(()=>{fetch(ajaxurl,{method:"POST",credentials:"same-origin",body:fd}).then(r=>{if(!r.ok){dialog({message:__("Something when wrong..."),type:"error"});return}return r.json()}).then(r=>{if(!r.success){dialog({message:r.data[0].message,type:"error"});pushFiles();return}onUpload(r,file);filesUploaded.unshift(file);renderUploadedFiles();pushFiles()})},2e3)};const renderUploadingFiles=()=>{$("#uploading-files").html(filesToUpload.map(f=>`<div class="file"><span class="hourglass">⌛</span> ${f.name}</div>`))};const renderUploadedFiles=()=>{$("#uploaded-files").html(filesUploaded.map(f=>`<div class="file">✅ ${f.name}</div>`))};const addFiles=files=>{filesToUpload.push(...files);if(!uploading){pushFiles()}};const $input=$("#upload-file-input");$input.on("change",e=>{addFiles(e.target.files)});$("#select-files").on("click",e=>{e.preventDefault();$input.click()});const $droppable=$(".droppable-handler");$droppable.on("dragover",e=>{e.preventDefault();$droppable.addClass("dragover")}).on("dragleave",e=>{$droppable.removeClass("dragover")}).on("drop",e=>{e.preventDefault();$droppable.removeClass("dragover");let{dataTransfer}=e.originalEvent;addFiles(dataTransfer.files)})}})};const EmailPreviewModal=async(emailId,{height=window.innerHeight*.85,width=900})=>{const{close}=loadingModal();let email;try{email=await EmailsStore.maybeFetchItem(emailId)}catch(err){close();throw err}const{from_avatar,from_email,from_name,subject,built:content}=email.context;close();return ModalFrame({frameAttributes:{className:"gh-modal-frame gh-email-preview-modal"}},({close})=>Div({style:{width:`${width}px`,height:`${height}px`}},EmailPreview({close:close,from_avatar:from_avatar,from_email:from_email,from_name:from_name,subject:subject,content:content})))};const EmailPreview=({close=false,from_avatar,from_email,from_name,subject,content})=>{return Div({className:"email-preview"},[Div({className:"from-preview display-flex gap-20 has-box-shadow"},[makeEl("img",{src:from_avatar,className:"from-avatar",height:40,width:40,style:{borderRadius:"50%"}}),Div({className:"subject-and-from"},[`<h2>${subject}</h2>`,`<span class="from-name">${from_name}</span> <span class="from-email">&lt;${from_email}&gt;</span>`]),close!==false?Button({className:"gh-button secondary icon text",style:{marginLeft:"auto"},onClick:close},Dashicon("no-alt")):null]),Iframe({id:"desktop-preview-iframe"},content)])};$(()=>{$(document).on("click","a.gh-email-preview",e=>{e.preventDefault();let emailId=e.currentTarget.dataset.id??e.currentTarget.closest("tr").id;EmailPreviewModal(parseInt(emailId),{})});window.addEventListener("hashchange",e=>{let hash=window.location.hash.replace("#","");if(hash.startsWith("gh-email-preview/")){let emailId=hash.replace("gh-email-preview/","");EmailPreviewModal(parseInt(emailId),{})}})});const ImagePicker=({multiple=false,title=__("Select a image to upload"),selectText=__("Use this image"),onChange=attachment=>{}})=>{let file_frame=wp.media({title:title,button:{text:selectText},multiple:multiple});file_frame.on("select",function(){let attachment=file_frame.state().get("selection").first().toJSON();onChange(attachment)});file_frame.open()};const ImageInput=({id,name="src",onChange,value=""})=>{const handleChange=(value,attachment=null)=>{onChange(value,attachment);morphdom(document.getElementById(id),ImageInput({id:id,name:name,onChange:onChange,value:value}))};return Div({id:id,className:"image-picker"},[value?Div({id:`${id}-preview`,className:"image-input-preview",style:{backgroundImage:`url(${value})`},onClick:e=>{e.preventDefault();ImagePicker({multiple:false,onChange:attachment=>handleChange(attachment.url,attachment)})}}):null,InputGroup([Input({type:"text",id:`${id}-src`,value:value,className:"control full-width",name:name,onChange:e=>{handleChange(e.target.value,null)}}),Button({id:`${id}-select`,className:"gh-button secondary icon",onClick:e=>{e.preventDefault();ImagePicker({multiple:false,onChange:attachment=>handleChange(attachment.url,attachment)})}},icons.image)])])};const FeedbackModal=({subject="",message="",onSubmit=r=>{}})=>{const State=Groundhogg.createState({subject:subject,message:message,submitting:false});ModalWithHeader({width:"400px",header:"Send Feedback"},({close,morph})=>Form({className:"display-flex column gap-5",onSubmit:e=>{e.preventDefault();State.set({submitting:true});morph();Groundhogg.api.ajax({action:"gh_plugin_feedback",subject:State.subject,message:State.message}).then(r=>{onSubmit(r);dialog({message:"Thanks for your feedback!"});close()});return false}},[Label({for:"feedback-subject"},["What feature are you submitting feedback for?"]),Input({id:"feedback-subject",value:State.subject,required:true,onInput:e=>State.set({subject:e.target.value})}),Div(),Label({for:"feedback-message"},["What is your feedback? Be as descriptive as possible."]),Textarea({id:"feedback-message",value:State.message,required:true,rows:4,onInput:e=>State.set({message:e.target.value})}),Button({className:"gh-button primary",type:"submit",disabled:State.submitting},"Send feedback"),Pg({},"Your email address will be collected to validate your feedback, but will not be used beyond that.")]))};$(document).on("click","a.feedback-modal",e=>{e.preventDefault();const{subject="",message=""}=e.currentTarget.dataset;FeedbackModal({subject:subject,message:message})});const ContactPhone=(icon,number,extension="")=>number?Span({className:"contact-phone"},[icon,An({href:`tel:${number}`},number),extension?Span({className:"ext"},` x${extension}`):null]):null;const ContactListItem=(item,{extra=item=>null,...props}={})=>{let allTags=jsonCopy(item.tags);let showTags=allTags.splice(0,10);const{ID}=item;const{full_name,gravatar,date_created,email}=item.data;const{primary_phone="",primary_phone_extension="",mobile_phone="",company_phone="",company_phone_extension=""}=item.meta;return Div({className:`contact-list-item`,id:`contact-list-item-${ID}`,dataId:ID,...props},[Div({className:"display-flex gap-10"},[Img({className:"avatar",src:gravatar,alt:"avatar"}),Div({className:"display-flex column"},[Div({},[makeEl("h4",{style:{margin:0}},full_name),Span({className:"subscribed"},`&nbsp;— ${sprintf(__("Subscribed %s"),`<abbr title="${formatDateTime(date_created)}">${sprintf(__("%s ago "),item.i18n.created)}</abbr>`)}`)]),Div({},[An({href:`mailto:${email}`},email),Span({},[" — ",Span({className:`gh-text ${item.is_marketable?"green":"red"}`},Groundhogg.filters.optin_status[item.data.optin_status])])])])]),Div({className:"show-on-hover"},[primary_phone||company_phone||mobile_phone?Div({className:"contact-phones"},[ContactPhone(icons.mobile,mobile_phone),ContactPhone(icons.phone,primary_phone,primary_phone_extension),ContactPhone(icons.phone,company_phone,company_phone_extension)]):null,Div({className:"gh-tags"},[...showTags.map(tag=>Span({className:"gh-tag"},tag.data.tag_name)),allTags.length?Span({},sprintf("and %d more...",allTags.length)):null]),maybeCall(extra,item)])])};const ContactList=(contacts=[],{noContacts=()=>null,itemProps={}}={})=>{if(!contacts.length){return maybeCall(noContacts)}return Div({className:"contact-list"},contacts.map(contact=>ContactListItem(contact,maybeCall(itemProps,contact))))};const QuickSearch=({itemProps={},queryOverrides={}}={})=>{const State=Groundhogg.createState({search:"",searched:false,results:[],loaded:false});const fetchResults=async()=>{let results=await ContactsStore.fetchItems({search:State.search,orderby:"date_created",order:"DESC",limit:5,...queryOverrides});State.set({results:results,searched:true,loaded:true})};return Div({id:"quick-search-wrap"},morph=>{if(!State.loaded){fetchResults().then(morph)}const updateResults=debounce(async()=>{await fetchResults();morph()},300);return Fragment([Form({action:adminPageURL("gh_contacts")},[Input({type:"hidden",name:"page",value:"gh_contacts"}),Input({id:"quick-search-input",placeholder:__("Search by name or email...","groundhogg"),type:"search",name:"s",value:State.search,onInput:e=>{State.set({search:e.target.value});updateResults()}})]),State.loaded?null:Skeleton({},["full","full","full"]),State.results.length?ContactList(State.results,{itemProps:item=>({className:"contact-list-item clickable",onClick:e=>{window.open(item.admin,"_self")},...maybeCall(itemProps,item)})}):null,State.results.length===0&&State.searched?Pg({style:{textAlign:"center"}},__("No contacts found for the current search","groundhogg")):null])})};const Panel=({id,name,collapsed=false,hidden=false,onCollapse=id=>{}},content)=>{if(hidden){return null}return Div({id:`${id}-panel`,className:`gh-panel ${collapsed?"closed":""}`},[Div({className:`gh-panel-header`},[H2({},name),Button({className:"toggle-indicator",onClick:e=>{onCollapse(id)}})]),collapsed?null:maybeCall(content)])};const Panels=overrides=>({...Groundhogg.createRegistry({}),storagePrefix:"gh-panels",collapse(id){if(!this.isCollapsed(id)){this.toggleCollapse(id)}},expand(id){if(this.isCollapsed(id)){this.toggleCollapse(id)}},hide(id){if(!this.isHidden(id)){this.toggleHidden(id)}},show(id){if(this.isHidden(id)){this.toggleHidden(id)}},togglePanel(id,suffix){let panels=this.getPanelIds(suffix);if(panels.includes(id)){panels.splice(panels.indexOf(id),1)}else{panels.push(id)}localStorage.setItem(`${this.storagePrefix}-${suffix}`,JSON.stringify(panels))},toggleHidden(id){this.togglePanel(id,"hidden")},toggleCollapse(id){this.togglePanel(id,"collapsed")},getPanelIds(suffix){return JSON.parse(localStorage.getItem(`${this.storagePrefix}-${suffix}`))||[]},getHiddenPanelIds(){return this.getPanelIds("hidden")},getCollapsedPanelIds(){return this.getPanelIds("collapsed")},isHidden(id){return this.getHiddenPanelIds().includes(id)},isCollapsed(id){return this.getCollapsedPanelIds().includes(id)},PanelControls(){return Div({},[...this.map((item,id)=>Div({className:"display-flex gap-10",style:{marginBottom:"10px"}},[Toggle({checked:!this.isHidden(id),id:`toggle-${id}`,onChange:e=>{this.toggleHidden(id)}}),Label({for:`toggle-${id}`},item.name)]))])},Panel(id){let{content,...panel}=this.get(id);return Panel({id:id,...panel,collapsed:this.isCollapsed(id),hidden:this.isHidden(id),onCollapse:id=>{this.toggleCollapse(id);morphdom(document.getElementById(`${id}-panel`),this.Panel(id))}},content)},Panels(){return Div({className:"display-flex column gap-20",id:this.storagePrefix},this.keys().map(id=>this.Panel(id)))},...overrides});const Relationships=({title="",id,store,child_type="",parent_type="",renderItem=item=>{},onAddItem=(r,j)=>{}})=>{const rel_type_key=child_type?"child_type":"parent_type";const rel_type=child_type||parent_type;const rel_id_key=child_type?"child_id":"parent_id";const State=Groundhogg.createState({loaded:false,items:[]});const fetchRelationships=()=>store.fetchRelationships(id,{[rel_type_key]:rel_type}).then(items=>State.set({items:items,loaded:true}));const deleteRelationship=itemId=>store.deleteRelationships(id,{[rel_type_key]:rel_type,[rel_id_key]:itemId}).then(()=>State.set({items:State.items.filter(item=>item.ID!==itemId)}));const createRelationship=item=>store.createRelationships(id,{[rel_type_key]:rel_type,[rel_id_key]:item.ID}).then(()=>State.set({items:[...State.items,item]}));return Div({id:`${rel_type_key}-${rel_type}-rel-of-${id}`,className:`display-flex column relationship-editor ${rel_type_key}-${rel_type}`},morph=>{const handleDeleteRelationship=itemId=>deleteRelationship(itemId).then(morph);if(!State.loaded){fetchRelationships().then(morph);return Skeleton({},["full","full","full"])}const AddRelButton=()=>Button({id:`add-${rel_type_key}-${rel_type}-rel-for-${id}`,className:"gh-button secondary text icon",onClick:e=>{let promise=new Promise((resolve,reject)=>onAddItem(resolve,reject,State));promise.then(item=>createRelationship(item).then(morph))}},[Dashicon("plus-alt2"),ToolTip(__("Add relationship","groundhogg"),"left")]);return Fragment([title?Div({className:"space-between"},[H4({},title),AddRelButton()]):null,...State.items.map(item=>renderItem({...item,onDelete:handleDeleteRelationship})),title?null:Div({className:"display-flex flex-end"},AddRelButton())])})};const OwnerPicker=({id="select-owners",selected=[],onChange=ids=>{},allow0=true,itemDisplay=user=>user.data.display_name,multiple=true,...overrides})=>ItemPicker({id:`select-users`,noneSelected:__("Select a user...","groundhogg"),selected:selected.map(user_id=>{if(user_id==0&&allow0){return{id:0,text:__("The contact owner","groundhogg")}}return{id:user_id,text:itemDisplay(getOwner(user_id))}}),multiple:multiple,style:{flexGrow:1},isValidSelection:id=>id===0||getOwner(id),fetchOptions:search=>{search=new RegExp(search,"i");let options=Groundhogg.filters.owners.map(u=>({id:u.ID,text:itemDisplay(u)}));if(allow0){options.push({id:0,text:__("The contact owner","groundhogg")})}options=options.filter(({text})=>text.match(search));return Promise.resolve(options)},onChange:items=>{if(multiple){onChange(items.map(({id})=>id));return}onChange(items)},...overrides});function getClosestRelativeAncestor(element){let parent=element.parentElement;while(parent){if(window.getComputedStyle(parent).position==="relative"){return parent}parent=parent.parentElement}return null}const Tour=(steps,{onFinish=()=>{},beforeDismiss=({dismiss})=>dismiss(),onDismiss=()=>{},fixed=false})=>{const State=Groundhogg.createState({current:0,step:null,target:null,relative:null});const currentStep=()=>steps[State.current];const removeSteps=()=>{document.querySelectorAll(".tour-prompt-container").forEach(el=>el.remove());document.querySelectorAll(".tour-prompt").forEach(el=>el.remove());document.querySelectorAll(".tour-highlighted").forEach(el=>el.classList.remove("tour-highlighted"))};const remove=()=>{removeSteps();document.removeEventListener("resize",rePositionStep);document.removeEventListener("scroll",rePositionStep)};const dismiss=async()=>{remove();onDismiss()};const next=()=>{const{onNext=()=>{}}=currentStep();onNext();if(State.current+1>=steps.length){remove();onFinish(true);return}State.current++;showStep()};const prev=()=>{const{onPrev=()=>{}}=currentStep();onPrev();if(State.current<=0){return}State.current--;showStep()};const showStep=()=>{removeSteps();positionStep()};function rePositionStep(){let{position}=currentStep();let{target,relative,step,windowEl}=State;const targetPos=target.getBoundingClientRect();const relativePos=relative.getBoundingClientRect();const stepPos=step.getBoundingClientRect();const gap=20;if(fixed){windowEl.style.height=`${targetPos.height+gap*2}px`;windowEl.style.width=`${targetPos.width+gap*2}px`;windowEl.style.borderWidth=`${Math.round(targetPos.y)-gap}px ${Math.round(window.innerWidth-targetPos.x)-gap}px ${Math.round(window.innerHeight-targetPos.y)-gap}px ${Math.round(targetPos.x)-gap}px`;switch(position){case"right":step.style.left=`${targetPos.x+targetPos.width+gap}px`;step.style.top=`${targetPos.y}px`;break;case"left":step.style.left=`${targetPos.x-stepPos.width-gap}px`;step.style.top=`${targetPos.y}px`;break;case"above":step.style.left=`${targetPos.x}px`;step.style.top=`${targetPos.y-stepPos.height-gap}px`;break;case"below":step.style.left=`${targetPos.x}px`;step.style.top=`${targetPos.y+targetPos.height+gap}px`;break;case"below-left":step.style.left=`${targetPos.x+targetPos.width-stepPos.width}px`;step.style.top=`${targetPos.y+targetPos.height+gap}px`;break}return}switch(position){case"right":step.style.left=`${targetPos.right-relativePos.left+gap}px`;step.style.top=`${targetPos.top-relativePos.top}px`;break;case"left":step.style.left=`${targetPos.left-relativePos.left-stepPos.width-gap}px`;step.style.top=`${targetPos.top-relativePos.top}px`;break;case"above":step.style.left=`${targetPos.left-relativePos.left}px`;step.style.top=`${targetPos.top-relativePos.top-stepPos.height-gap}px`;break;case"below":step.style.left=`${targetPos.left-relativePos.left}px`;step.style.top=`${targetPos.bottom-relativePos.top+gap}px`;break;case"below-left":step.style.left=`${targetPos.right-relativePos.left-stepPos.width}px`;step.style.top=`${targetPos.bottom-relativePos.top+gap}px`;break}}function positionStep(){let tourEl=TourStep();let windowEl=tourEl.querySelector(".tour-window");let stepEl=tourEl.querySelector(".tour-prompt");let{target,relative,onInit=()=>{},onBefore=()=>{}}=currentStep();target=document.querySelector(target);if(!target){next();return}if(fixed){relative=document.body}else if(relative){relative=target.closest(relative)}else{relative=getClosestRelativeAncestor(target)}stepEl.style.position=fixed?"fixed":"absolute";if(fixed){relative.append(tourEl)}else{target.classList.add("tour-highlighted");relative.append(stepEl)}target.scrollIntoView({behavior:"instant",block:"center",inline:"center"});onBefore({next:next,prev:prev,target:target,relative:relative,step:stepEl,windowEl:windowEl,currentStep:currentStep});State.set({step:stepEl,windowEl:windowEl,target:target,relative:relative});rePositionStep();onInit({next:next,prev:prev,target:target,relative:relative,step:stepEl,windowEl:windowEl,currentStep:currentStep});stepEl.querySelector("#tour-next").focus()}const TourStep=()=>MakeEl.Div({className:"tour-prompt-container"},[fixed?MakeEl.Div({className:"tour-window"},[MakeEl.Div({className:"tour-window-shadow",onClick:next})]):null,MakeEl.Div({className:`tour-prompt ${currentStep().position}`,style:{padding:"10px",width:"200px"}},[MakeEl.Button({className:"dismiss",onClick:e=>{beforeDismiss({dismiss:dismiss,State:State})}},MakeEl.Dashicon("no-alt")),MakeEl.Div({},currentStep().prompt),MakeEl.Div({className:"display-flex flex-end gap-5 space-above-10"},[State.current>0?MakeEl.Button({id:"tour-prev",className:"gh-button small secondary text prev-step",onClick:()=>prev()},"Prev"):null,currentStep().showNext===false?null:MakeEl.Button({id:"tour-next",className:`gh-button small ${State.current<steps.length-1?"secondary":"primary"} next-step`,onClick:()=>next()},State.current<steps.length-1?"Next":"Finish")])])]);document.addEventListener("resize",rePositionStep);document.addEventListener("scroll",rePositionStep);positionStep()};Groundhogg.components={QuickSearch:QuickSearch,addContactModal:addContactModal,internalForm:internalForm,betterTagPicker:betterTagPicker,quickAddForm:quickAddForm,selectContactModal:selectContactModal,quickEditContactModal:quickEditContactModal,makeInput:makeInput,emailModal:emailModal,EmailTemplateModal:EmailTemplateModal,fileUploader:fileUploader,EmailPreview:EmailPreview,EmailPreviewModal:EmailPreviewModal,ImageInput:ImageInput,ImagePicker:ImagePicker,FeedbackModal:FeedbackModal,ContactList:ContactList,ContactListItem:ContactListItem,Panel:Panel,Panels:Panels,Relationships:Relationships,OwnerPicker:OwnerPicker,Tour:Tour}})(jQuery);
  • groundhogg/tags/4.2.12/assets/js/admin/emails/email-block-editor.js

    r3395861 r3458296  
    96439643    discord    : 'Discord',
    96449644    rumble     : 'Rumble',
     9645    bluesky    : 'Bluesky',
    96459646  }
    96469647
  • groundhogg/tags/4.2.12/assets/js/admin/emails/email-block-editor.min.js

    r3395861 r3458296  
    195195          `]),`<!-- /wp:query -->`]).innerHTML},defaults:{layout:"cards",featured:true,excerpt:false,thumbnail:true,thumbnail_size:"thumbnail",columns:2,gap:20,cardStyle:{},headingStyle:fontDefaults({fontSize:24}),excerptStyle:fontDefaults({fontSize:16}),queryId:"",post_type:"post",number:5,offset:0}});const ChildBlocks=({children})=>Div({className:`children sortable-blocks ${children.length?"":"empty"}`,onCreate:el=>{makeSortable(el)}},[...children.map(b=>EditBlockWrapper(b))]);const QueryLoopContent=({DynamicContent,...block})=>{let dynamicContent=Div({},DynamicContent());let childBlockPlace=dynamicContent.querySelector(".replace-with-child-blocks");if(!childBlockPlace){return dynamicContent.firstElementChild}childBlockPlace.replaceWith(ChildBlocks(block));return Fragment([dynamicContent.firstElementChild])};const PostTagReference=[{tag:"the_title",desc:"The post title"},{tag:"the_excerpt",desc:"The post excerpt"},{tag:"the_url",desc:"The link to the post"},{tag:"the_thumbnail",desc:"The thumbnail image"},{tag:"the_thumbnail_url",desc:"The thumbnail image URL"},{tag:"the_content",desc:"The post content"},{tag:"the_id",desc:"The post ID"},{tag:"the_date",desc:"The post publish date"},{tag:"the_author",desc:"The post author"},{tag:"read_more",desc:'A "Read more" link to the post'}];registerDynamicBlock("queryloop","Query Loop",{svg:`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
    196196  <path fill="currentColor" d="M18 7a7.669 7.669 0 0 0-6 3.19A7.669 7.669 0 0 0 6 7c-3.687 0-5 2.583-5 5 0 3.687 2.583 5 5 5a7.669 7.669 0 0 0 6-3.19A7.669 7.669 0 0 0 18 17c2.417 0 5-1.313 5-5 0-2.417-1.313-5-5-5ZM6 15a2.689 2.689 0 0 1-3-3 2.689 2.689 0 0 1 3-3c2.579 0 4.225 2.065 4.837 3-.612.935-2.258 3-4.837 3Zm12 0c-2.579 0-4.225-2.065-4.837-3 .612-.935 2.258-3 4.837-3a2.689 2.689 0 0 1 3 3 2.689 2.689 0 0 1-3 3Z"/>
    197 </svg>`,attributes:{children:el=>{let blockTable=el.querySelector("table:not(.email-columns)");return parseBlocksFromTable(blockTable)}},controls:({gap=10,columns=2,thumbnail_size="post-thumbnail",updateBlock,...query})=>{return Fragment([ControlGroup({id:"queryloop-layout",name:"Layout"},[Control({label:"Columns"},NumberControl({id:"columns",className:"control-input",value:columns,step:1,onInput:e=>updateBlock({columns:e.target.value})})),Control({label:"Gap"},NumberControl({id:"column-gap",className:"control-input",value:gap,step:5,unit:"px",onInput:e=>updateBlock({gap:e.target.value})})),Control({label:"Thumbnail Size"},Select({id:"thumbnail-size",style:{width:"115px"},selected:thumbnail_size,options:imageSizes.map(size=>({value:size,text:size})),onChange:e=>updateBlock({thumbnail_size:e.target.value})}))]),QueryControls({updateBlock:updateBlock,...query}),ControlGroup({id:"queryloop-reference",name:"Reference"},[Pg({},"Use the below merge tags to merge post data within the query loop."),...PostTagReference.map(tag=>Div({className:"display-flex space-between"},[makeEl("code",{className:"copy-text"},`#${tag.tag}#`),Span({className:"tag-desc"},tag.desc)]))])])},edit:QueryLoopContent,html:({DynamicContent,...block})=>{if(isGeneratingHTML()){return renderBlocksHTML(block.children)}return QueryLoopContent({DynamicContent:DynamicContent,...block})},plainText:({children=[]})=>renderBlocksPlainText(children),defaults:{children:[createBlock("text",{content:`<p>#the_thumbnail#</p>\n<h2>#the_title#</h2>\n<p>#the_excerpt#</p>\n<p>#read_more#</p>`})],columns:2,layout:"grid",queryId:"",post_type:"post",number:6,offset:0,thumbnail_size:"post-thumbnail"}});const socialIcons={facebook:"Facebook",instagram:"Instagram",linkedin:"LinkedIn",pinterest:"Pinterest",reddit:"Reddit",threads:"Threads",tiktok:"TikTok",tumblr:"Tumblr",twitch:"Twitch",twitter:"𝕏",vimeo:"Vimeo",whatsapp:"WhatsApp",wordpress:"WordPress",youtube:"YouTube",github:"GitHub",truthsocial:"Truth Social",odysee:"Odysee",discord:"Discord",rumble:"Rumble"};const socialIconThemes={"brand-boxed":"Brand Colors Square","brand-circle":"Brand Colors Circular","brand-icons":"Brand Colors Icons","black-boxed":"Black Boxed","black-circle":"Black Circular","black-icons":"Black Icons","dark-grey-boxed":"Gray Boxed","dark-grey-circle":"Gray Circle","dark-grey-icons":"Gray Icons","grey-boxed":"Gray Boxed","grey-circle":"Gray Circle","grey-icons":"Gray Icons","white-boxed":"White Boxed","white-circle":"White Circular","white-icons":"White Icons"};const SocialIcon=(icon,theme="brand-circle",size=20)=>makeEl("img",{src:`${Groundhogg.assets.images}/social-icons/${theme}/${icon||"facebook"}.png`,alt:socialIcons[icon],height:size,width:size,style:{verticalAlign:"bottom"}});const SocialIconTheme=(theme,selected,updateBlock)=>{let themeIcons=["facebook","instagram","twitter"];let{use="global",socials=[]}=getActiveBlock();if(use==="global"&&globalSocials.length>=3){themeIcons=globalSocials.map(([social])=>social).slice(0,3)}else if(use==="custom"&&socials.length>=3){themeIcons=socials.map(([social])=>social).slice(0,3)}return Button({id:`select-${theme}`,title:socialIconThemes[theme],className:`gh-button ${theme===selected?"primary":"secondary text"} social-icon-theme ${theme}`,onClick:e=>updateBlock({theme:theme,morphControls:true})},themeIcons.map(icon=>SocialIcon(icon,theme,20)))};const SocialLinksRepeater=({socials,theme,onChange})=>InputRepeater({id:"social-links",rows:socials,cells:[({setValue,value,id,...props})=>Button({className:"gh-button grey icon",id:id,onClick:e=>{theme=hasActiveBlock()?getActiveBlock().theme:"brand-boxed";MiniModal({selector:`#${id}`},({close})=>Div({className:`display-grid social-icon-picker ${theme}`},[...Object.keys(socialIcons).map(social=>Button({title:socialIcons[social],id:`${id}-${social}`,className:"gh-button secondary text dashicon span-3",onClick:e=>{setValue(social);close()}},SocialIcon(social,theme)))]))}},SocialIcon(value||"facebook",theme)),({setValue,...props},[icon])=>Input({type:"url",placeholder:`https://${icon}.com/your-profile/`,...props})],sortable:true,onChange:onChange});registerBlock("social","Socials",{attributes:{size:el=>parseInt(el.querySelector("img")?.width),gap:el=>parseInt(el.querySelector("td.gap")?.width),theme:el=>el.querySelector("img")?.src.split("/").at(-2),socials:el=>Array.from(el.querySelectorAll("a")).map(el=>{let png=el.firstElementChild.src.split("/").at(-1);return[png.substr(0,png.indexOf(".png")),el.href]})},svg:`
     197</svg>`,attributes:{children:el=>{let blockTable=el.querySelector("table:not(.email-columns)");return parseBlocksFromTable(blockTable)}},controls:({gap=10,columns=2,thumbnail_size="post-thumbnail",updateBlock,...query})=>{return Fragment([ControlGroup({id:"queryloop-layout",name:"Layout"},[Control({label:"Columns"},NumberControl({id:"columns",className:"control-input",value:columns,step:1,onInput:e=>updateBlock({columns:e.target.value})})),Control({label:"Gap"},NumberControl({id:"column-gap",className:"control-input",value:gap,step:5,unit:"px",onInput:e=>updateBlock({gap:e.target.value})})),Control({label:"Thumbnail Size"},Select({id:"thumbnail-size",style:{width:"115px"},selected:thumbnail_size,options:imageSizes.map(size=>({value:size,text:size})),onChange:e=>updateBlock({thumbnail_size:e.target.value})}))]),QueryControls({updateBlock:updateBlock,...query}),ControlGroup({id:"queryloop-reference",name:"Reference"},[Pg({},"Use the below merge tags to merge post data within the query loop."),...PostTagReference.map(tag=>Div({className:"display-flex space-between"},[makeEl("code",{className:"copy-text"},`#${tag.tag}#`),Span({className:"tag-desc"},tag.desc)]))])])},edit:QueryLoopContent,html:({DynamicContent,...block})=>{if(isGeneratingHTML()){return renderBlocksHTML(block.children)}return QueryLoopContent({DynamicContent:DynamicContent,...block})},plainText:({children=[]})=>renderBlocksPlainText(children),defaults:{children:[createBlock("text",{content:`<p>#the_thumbnail#</p>\n<h2>#the_title#</h2>\n<p>#the_excerpt#</p>\n<p>#read_more#</p>`})],columns:2,layout:"grid",queryId:"",post_type:"post",number:6,offset:0,thumbnail_size:"post-thumbnail"}});const socialIcons={facebook:"Facebook",instagram:"Instagram",linkedin:"LinkedIn",pinterest:"Pinterest",reddit:"Reddit",threads:"Threads",tiktok:"TikTok",tumblr:"Tumblr",twitch:"Twitch",twitter:"𝕏",vimeo:"Vimeo",whatsapp:"WhatsApp",wordpress:"WordPress",youtube:"YouTube",github:"GitHub",truthsocial:"Truth Social",odysee:"Odysee",discord:"Discord",rumble:"Rumble",bluesky:"Bluesky"};const socialIconThemes={"brand-boxed":"Brand Colors Square","brand-circle":"Brand Colors Circular","brand-icons":"Brand Colors Icons","black-boxed":"Black Boxed","black-circle":"Black Circular","black-icons":"Black Icons","dark-grey-boxed":"Gray Boxed","dark-grey-circle":"Gray Circle","dark-grey-icons":"Gray Icons","grey-boxed":"Gray Boxed","grey-circle":"Gray Circle","grey-icons":"Gray Icons","white-boxed":"White Boxed","white-circle":"White Circular","white-icons":"White Icons"};const SocialIcon=(icon,theme="brand-circle",size=20)=>makeEl("img",{src:`${Groundhogg.assets.images}/social-icons/${theme}/${icon||"facebook"}.png`,alt:socialIcons[icon],height:size,width:size,style:{verticalAlign:"bottom"}});const SocialIconTheme=(theme,selected,updateBlock)=>{let themeIcons=["facebook","instagram","twitter"];let{use="global",socials=[]}=getActiveBlock();if(use==="global"&&globalSocials.length>=3){themeIcons=globalSocials.map(([social])=>social).slice(0,3)}else if(use==="custom"&&socials.length>=3){themeIcons=socials.map(([social])=>social).slice(0,3)}return Button({id:`select-${theme}`,title:socialIconThemes[theme],className:`gh-button ${theme===selected?"primary":"secondary text"} social-icon-theme ${theme}`,onClick:e=>updateBlock({theme:theme,morphControls:true})},themeIcons.map(icon=>SocialIcon(icon,theme,20)))};const SocialLinksRepeater=({socials,theme,onChange})=>InputRepeater({id:"social-links",rows:socials,cells:[({setValue,value,id,...props})=>Button({className:"gh-button grey icon",id:id,onClick:e=>{theme=hasActiveBlock()?getActiveBlock().theme:"brand-boxed";MiniModal({selector:`#${id}`},({close})=>Div({className:`display-grid social-icon-picker ${theme}`},[...Object.keys(socialIcons).map(social=>Button({title:socialIcons[social],id:`${id}-${social}`,className:"gh-button secondary text dashicon span-3",onClick:e=>{setValue(social);close()}},SocialIcon(social,theme)))]))}},SocialIcon(value||"facebook",theme)),({setValue,...props},[icon])=>Input({type:"url",placeholder:`https://${icon}.com/your-profile/`,...props})],sortable:true,onChange:onChange});registerBlock("social","Socials",{attributes:{size:el=>parseInt(el.querySelector("img")?.width),gap:el=>parseInt(el.querySelector("td.gap")?.width),theme:el=>el.querySelector("img")?.src.split("/").at(-2),socials:el=>Array.from(el.querySelectorAll("a")).map(el=>{let png=el.firstElementChild.src.split("/").at(-1);return[png.substr(0,png.indexOf(".png")),el.href]})},svg:`
    198198        <svg viewBox="-33 0 512 512.001" xmlns="http://www.w3.org/2000/svg">
    199199            <path fill="currentColor"
  • groundhogg/tags/4.2.12/groundhogg.php

    r3442828 r3458296  
    44 * Plugin URI: https://www.groundhogg.io/?utm_source=wp-plugins&utm_campaign=plugin-uri&utm_medium=wp-dash
    55 * Description: CRM and marketing automation for WordPress
    6  * Version: 4.2.11
     6 * Version: 4.2.12
    77 * Author: Groundhogg Inc.
    88 * Author URI: https://www.groundhogg.io/?utm_source=wp-plugins&utm_campaign=author-uri&utm_medium=wp-dash
     
    2525if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
    2626
    27 define( 'GROUNDHOGG_VERSION', '4.2.11' );
    28 define( 'GROUNDHOGG_PREVIOUS_STABLE_VERSION', '4.2.10' );
     27define( 'GROUNDHOGG_VERSION', '4.2.12' );
     28define( 'GROUNDHOGG_PREVIOUS_STABLE_VERSION', '4.2.11' );
    2929
    3030define( 'GROUNDHOGG__FILE__', __FILE__ );
  • groundhogg/tags/4.2.12/includes/classes/funnel.php

    r3343709 r3458296  
    642642        }
    643643
    644         $last_changed = db()->steps->cache_get_last_changed();
    645         $cache_key    = "$this->ID:steps:$last_changed:" . md5serialize( $query );
    646         $steps        = wp_cache_get( $cache_key, db()->steps->get_cache_group(), false, $found );
    647 
    648         // make sure all items in array are also steps
    649         if ( $found && is_array( $steps ) && array_all( $steps, function ( $step ) {
    650                 return is_a( $step, Step::class );
    651             } ) ) {
    652 
    653             return $steps;
    654         }
     644//      $last_changed = db()->steps->cache_get_last_changed();
     645//      $cache_key    = "$this->ID:steps:$last_changed:" . md5serialize( $query );
     646//      $steps        = wp_cache_get( $cache_key, db()->steps->get_cache_group(), false, $found );
     647//
     648//        // make sure all items in array are also steps
     649//      if ( $found && is_array( $steps ) && array_all( $steps, function ( $step ) {
     650//              return is_a( $step, Step::class );
     651//          } ) ) {
     652//
     653//          return $steps;
     654//      }
    655655
    656656        $steps = $this->get_steps_db()->query( $query );
     
    674674        }
    675675
    676         wp_cache_set( $cache_key, $steps, db()->steps->get_cache_group(), MINUTE_IN_SECONDS );
     676//      wp_cache_set( $cache_key, $steps, db()->steps->get_cache_group(), MINUTE_IN_SECONDS );
    677677
    678678        return $steps;
  • groundhogg/tags/4.2.12/includes/form/form-v2.php

    r3400645 r3458296  
    19031903    protected $hidden_fields = [];
    19041904
     1905    public function is_turnstile_enabled() {
     1906        $turnstile = get_array_var( $this->get_cleaned_json_config(), 'turnstile', [] );
     1907        return isset_not_empty( $turnstile, 'enabled' ) && is_recaptcha_enabled();
     1908    }
     1909
     1910    public function is_recaptcha_enabled() {
     1911        $recaptcha = get_array_var( $this->get_cleaned_json_config(), 'recaptcha', [] );
     1912        return isset_not_empty( $recaptcha, 'enabled' ) && is_recaptcha_enabled();
     1913    }
     1914
     1915    /**
     1916     * Get a cleaned assoc array of the form config
     1917     *
     1918     * @return array
     1919     */
     1920    private function get_cleaned_json_config() {
     1921        $config = $this->get_meta( 'form' );
     1922        // encode and decode to fix potential mutation errors when importing/exporting
     1923        return json_decode( wp_json_encode( $config ), true );
     1924    }
     1925
    19051926    /**
    19061927     * Get the HTML For the fields
     
    19091930     */
    19101931    function get_field_html() {
    1911 
    1912         $config = $this->get_meta( 'form' );
    1913 
    1914         $config = json_decode( wp_json_encode( $config ), true );
    1915 
     1932        $config = $this->get_cleaned_json_config();
    19161933        $fields = get_array_var( $config, 'fields', [] );
    19171934
     
    22032220     */
    22042221    public function get_fields() {
    2205         $config = json_decode( wp_json_encode( $this->get_meta( 'form' ) ), true );
     2222        $config = $this->get_cleaned_json_config();
    22062223
    22072224        if ( ! is_array( $config ) || ! isset( $config['fields'] ) ) {
     
    22292246
    22302247        // Ensure array and not stdClass
    2231         $config    = json_decode( wp_json_encode( $this->get_meta( 'form' ) ), true );
     2248        $config    = $this->get_cleaned_json_config();
    22322249        $fields    = $config['fields'];
    2233         $recaptcha = $config['recaptcha'];
    2234         $turnstile = $config['turnstile'];
    2235 
    2236         if ( $recaptcha['enabled'] ) {
    2237             $fields[] = $recaptcha;
    2238         }
    2239 
    2240         if ( $turnstile['enabled'] ) {
    2241             $fields[] = $turnstile;
     2250
     2251        // add the recaptcha to fields array for validation
     2252        if ( isset( $config[ 'recaptcha' ] ) &&  $config[ 'recaptcha' ]['enabled'] ){
     2253            $fields[] = $config['recaptcha'];
     2254        }
     2255
     2256        // add the turnstile to fields array for validation
     2257        if ( isset( $config[ 'turnstile' ] ) &&  $config[ 'turnstile' ]['enabled'] ){
     2258            $fields[] = $config['turnstile'];
    22422259        }
    22432260
  • groundhogg/tags/4.2.12/includes/functions.php

    r3442828 r3458296  
    25902590 * @return false|Contact
    25912591 */
    2592 function update_contact_with_map( $contact, array $fields, array $map = [], $submission = [] ) {
     2592function update_contact_with_map( mixed $contact, array $fields, array $map = [], array $submission = [] ) {
    25932593    return generate_contact_with_map( $fields, $map, $submission, $contact );
    25942594}
     
    25992599 * @throws \Exception
    26002600 *
    2601  * @param              $fields     array the raw data from the source
    2602  * @param              $map        array map of field_ids to contact keys
     2601 * @param  array       $fields    the raw data from the source
     2602 * @param  array       $map        map of field_ids to contact keys
    26032603 * @param array        $submission settings for the submission
    26042604 * @param null|Contact $contact    an existing contact record to modify
     
    26062606 * @return Contact|false
    26072607 */
    2608 function generate_contact_with_map( $fields, $map = [], $submission = [], $contact = null ) {
     2608function generate_contact_with_map( array $fields, array $map = [], array $submission = [], mixed $contact = null ) {
    26092609
    26102610    if ( empty( $map ) ) {
     
    38623862 *
    38633863 * @param string $call_name   the name you wish to call
    3864  * @param string $id_or_email id or email of the contact
     3864 * @param string|int|Contact $id_or_email id or email of the contact
    38653865 * @param bool   $by_user_id  whether the ID is the ID of a WP user
    38663866 */
     
    82738273 */
    82748274function verify_admin_ajax_nonce() {
    8275     return wp_verify_nonce( get_request_var( 'gh_admin_ajax_nonce' ), 'admin_ajax' );
     8275    return check_ajax_referer( 'admin_ajax', 'gh_admin_ajax_nonce', false );
    82768276}
    82778277
  • groundhogg/trunk/README.txt

    r3442828 r3458296  
    77Tested up to: 6.9
    88Requires PHP: 7.1
    9 Stable tag: 4.2.10
     9Stable tag: 4.2.12
    1010License: GPLv3
    1111License URI: https://www.gnu.org/licenses/gpl.md
     
    378378
    379379== Changelog ==
     380
     381= 4.2.12 (2026-02-10) =
     382* ADDED Bluesky social icons for the email editor.
     383* ADDED Bulk delete bulk action for campaigns.
     384* FIXED Email preview link stopped working in the emails table.
     385* FIXED Notice generated by improper array access check when submitting a form.
    380386
    381387= 4.2.11 (2026-01-19) =
  • groundhogg/trunk/admin/broadcasts/broadcasts-table.php

    r3400645 r3458296  
    245245
    246246        if ( $broadcast->is_email() ){
    247             $actions[] = html()->a( '#', esc_html__( 'Preview', 'groundhogg' ), [ 'class' => 'gh-email-preview', 'data-id' => $broadcast->get_object_id() ] );
     247            $actions[] = html()->a( '#gh-email-preview/' . $broadcast->get_object_id(), esc_html__( 'Preview', 'groundhogg' ) );
    248248        }
    249249
  • groundhogg/trunk/admin/campaigns/campaigns-table.php

    r3343709 r3458296  
    4747        // Set parent defaults.
    4848        parent::__construct( array(
    49             'singular' => 'tag',     // Singular name of the listed records.
    50             'plural'   => 'tags',    // Plural name of the listed records.
     49            'singular' => 'campaign',     // Singular name of the listed records.
     50            'plural'   => 'campaigns',    // Plural name of the listed records.
    5151            'ajax'     => false,       // Does this table support ajax?
    5252        ) );
     53    }
     54
     55    /**
     56     * @return array An associative array containing all the bulk actions.
     57     */
     58    protected function get_bulk_actions() {
     59
     60        $actions = array(
     61            'delete' => _x( 'Delete', 'List table bulk action', 'groundhogg' ),
     62        );
     63
     64        return apply_filters( 'groundhogg/admin/campaigns/table/bulk_actions', $actions );
    5365    }
    5466
  • groundhogg/trunk/admin/emails/emails-table.php

    r3400645 r3458296  
    331331            default:
    332332                $actions[] = [ 'class' => 'edit', 'display' => esc_html__( 'Edit' , 'groundhogg' ), 'url' => $item->admin_link() ];
    333                 $actions[] = [ 'class' => 'gh-email-preview', 'display' => esc_html__( 'Preview' , 'groundhogg' ), 'url' => '#' ];
     333                $actions[] = [ 'class' => 'gh-email-preview', 'display' => esc_html__( 'Preview' , 'groundhogg' ), 'url' => '#gh-email-preview/' . $item->get_id() ];
    334334                $actions[] = [
    335335                    'class'   => 'duplicate',
  • groundhogg/trunk/admin/reports/views/broadcast-single.php

    r3400645 r3458296  
    1717    <h1 class="report-title"><?php echo esc_html( $broadcast->get_title() ) ?></h1>
    1818    <?php if ( $broadcast->is_email() ): ?>
    19         <a href="#" class="gh-button secondary gh-email-preview" data-id="<?php echo esc_attr( $broadcast->get_object_id() ); ?>"><?php esc_html_e( 'Preview', 'groundhogg' ); ?></a>
     19        <a href="#gh-email-preview/<?php echo esc_attr( $broadcast->get_object_id() ); ?>" class="gh-button secondary"><?php esc_html_e( 'Preview', 'groundhogg' ); ?></a>
    2020    <?php endif; ?>
    2121</div>
  • groundhogg/trunk/assets/js/admin/components.js

    r3422142 r3458296  
    17961796      EmailPreviewModal(parseInt(emailId), {})
    17971797    })
     1798
     1799    window.addEventListener('hashchange', e => {
     1800      let hash = window.location.hash.replace('#', '')
     1801      if ( hash.startsWith('gh-email-preview/') ) {
     1802        let emailId = hash.replace('gh-email-preview/', '')
     1803        EmailPreviewModal(parseInt(emailId), {})
     1804      }
     1805    })
    17981806  })
    17991807
  • groundhogg/trunk/assets/js/admin/components.min.js

    r3422142 r3458296  
    216216      <div id="uploading-files"></div>
    217217      <div id="uploaded-files"></div>
    218       `,onOpen:({close})=>{let file=null;let filesToUpload=[];let filesUploaded=[];let uploading=false;const pushFiles=()=>{renderUploadingFiles();file=filesToUpload.pop();if(!file){uploading=false;return}uploading=true;let fd=new FormData;fd.append(fileName,file,file.name);fd.append("gh_admin_ajax_nonce",Groundhogg.nonces._adminajax);fd.append("action",action);beforeUpload(fd);setTimeout(()=>{fetch(ajaxurl,{method:"POST",credentials:"same-origin",body:fd}).then(r=>{if(!r.ok){dialog({message:__("Something when wrong..."),type:"error"});return}return r.json()}).then(r=>{if(!r.success){dialog({message:r.data[0].message,type:"error"});pushFiles();return}onUpload(r,file);filesUploaded.unshift(file);renderUploadedFiles();pushFiles()})},2e3)};const renderUploadingFiles=()=>{$("#uploading-files").html(filesToUpload.map(f=>`<div class="file"><span class="hourglass">⌛</span> ${f.name}</div>`))};const renderUploadedFiles=()=>{$("#uploaded-files").html(filesUploaded.map(f=>`<div class="file">✅ ${f.name}</div>`))};const addFiles=files=>{filesToUpload.push(...files);if(!uploading){pushFiles()}};const $input=$("#upload-file-input");$input.on("change",e=>{addFiles(e.target.files)});$("#select-files").on("click",e=>{e.preventDefault();$input.click()});const $droppable=$(".droppable-handler");$droppable.on("dragover",e=>{e.preventDefault();$droppable.addClass("dragover")}).on("dragleave",e=>{$droppable.removeClass("dragover")}).on("drop",e=>{e.preventDefault();$droppable.removeClass("dragover");let{dataTransfer}=e.originalEvent;addFiles(dataTransfer.files)})}})};const EmailPreviewModal=async(emailId,{height=window.innerHeight*.85,width=900})=>{const{close}=loadingModal();let email;try{email=await EmailsStore.maybeFetchItem(emailId)}catch(err){close();throw err}const{from_avatar,from_email,from_name,subject,built:content}=email.context;close();return ModalFrame({frameAttributes:{className:"gh-modal-frame gh-email-preview-modal"}},({close})=>Div({style:{width:`${width}px`,height:`${height}px`}},EmailPreview({close:close,from_avatar:from_avatar,from_email:from_email,from_name:from_name,subject:subject,content:content})))};const EmailPreview=({close=false,from_avatar,from_email,from_name,subject,content})=>{return Div({className:"email-preview"},[Div({className:"from-preview display-flex gap-20 has-box-shadow"},[makeEl("img",{src:from_avatar,className:"from-avatar",height:40,width:40,style:{borderRadius:"50%"}}),Div({className:"subject-and-from"},[`<h2>${subject}</h2>`,`<span class="from-name">${from_name}</span> <span class="from-email">&lt;${from_email}&gt;</span>`]),close!==false?Button({className:"gh-button secondary icon text",style:{marginLeft:"auto"},onClick:close},Dashicon("no-alt")):null]),Iframe({id:"desktop-preview-iframe"},content)])};$(()=>{$(document).on("click","a.gh-email-preview",e=>{e.preventDefault();let emailId=e.currentTarget.dataset.id??e.currentTarget.closest("tr").id;EmailPreviewModal(parseInt(emailId),{})})});const ImagePicker=({multiple=false,title=__("Select a image to upload"),selectText=__("Use this image"),onChange=attachment=>{}})=>{let file_frame=wp.media({title:title,button:{text:selectText},multiple:multiple});file_frame.on("select",function(){let attachment=file_frame.state().get("selection").first().toJSON();onChange(attachment)});file_frame.open()};const ImageInput=({id,name="src",onChange,value=""})=>{const handleChange=(value,attachment=null)=>{onChange(value,attachment);morphdom(document.getElementById(id),ImageInput({id:id,name:name,onChange:onChange,value:value}))};return Div({id:id,className:"image-picker"},[value?Div({id:`${id}-preview`,className:"image-input-preview",style:{backgroundImage:`url(${value})`},onClick:e=>{e.preventDefault();ImagePicker({multiple:false,onChange:attachment=>handleChange(attachment.url,attachment)})}}):null,InputGroup([Input({type:"text",id:`${id}-src`,value:value,className:"control full-width",name:name,onChange:e=>{handleChange(e.target.value,null)}}),Button({id:`${id}-select`,className:"gh-button secondary icon",onClick:e=>{e.preventDefault();ImagePicker({multiple:false,onChange:attachment=>handleChange(attachment.url,attachment)})}},icons.image)])])};const FeedbackModal=({subject="",message="",onSubmit=r=>{}})=>{const State=Groundhogg.createState({subject:subject,message:message,submitting:false});ModalWithHeader({width:"400px",header:"Send Feedback"},({close,morph})=>Form({className:"display-flex column gap-5",onSubmit:e=>{e.preventDefault();State.set({submitting:true});morph();Groundhogg.api.ajax({action:"gh_plugin_feedback",subject:State.subject,message:State.message}).then(r=>{onSubmit(r);dialog({message:"Thanks for your feedback!"});close()});return false}},[Label({for:"feedback-subject"},["What feature are you submitting feedback for?"]),Input({id:"feedback-subject",value:State.subject,required:true,onInput:e=>State.set({subject:e.target.value})}),Div(),Label({for:"feedback-message"},["What is your feedback? Be as descriptive as possible."]),Textarea({id:"feedback-message",value:State.message,required:true,rows:4,onInput:e=>State.set({message:e.target.value})}),Button({className:"gh-button primary",type:"submit",disabled:State.submitting},"Send feedback"),Pg({},"Your email address will be collected to validate your feedback, but will not be used beyond that.")]))};$(document).on("click","a.feedback-modal",e=>{e.preventDefault();const{subject="",message=""}=e.currentTarget.dataset;FeedbackModal({subject:subject,message:message})});const ContactPhone=(icon,number,extension="")=>number?Span({className:"contact-phone"},[icon,An({href:`tel:${number}`},number),extension?Span({className:"ext"},` x${extension}`):null]):null;const ContactListItem=(item,{extra=item=>null,...props}={})=>{let allTags=jsonCopy(item.tags);let showTags=allTags.splice(0,10);const{ID}=item;const{full_name,gravatar,date_created,email}=item.data;const{primary_phone="",primary_phone_extension="",mobile_phone="",company_phone="",company_phone_extension=""}=item.meta;return Div({className:`contact-list-item`,id:`contact-list-item-${ID}`,dataId:ID,...props},[Div({className:"display-flex gap-10"},[Img({className:"avatar",src:gravatar,alt:"avatar"}),Div({className:"display-flex column"},[Div({},[makeEl("h4",{style:{margin:0}},full_name),Span({className:"subscribed"},`&nbsp;— ${sprintf(__("Subscribed %s"),`<abbr title="${formatDateTime(date_created)}">${sprintf(__("%s ago "),item.i18n.created)}</abbr>`)}`)]),Div({},[An({href:`mailto:${email}`},email),Span({},[" — ",Span({className:`gh-text ${item.is_marketable?"green":"red"}`},Groundhogg.filters.optin_status[item.data.optin_status])])])])]),Div({className:"show-on-hover"},[primary_phone||company_phone||mobile_phone?Div({className:"contact-phones"},[ContactPhone(icons.mobile,mobile_phone),ContactPhone(icons.phone,primary_phone,primary_phone_extension),ContactPhone(icons.phone,company_phone,company_phone_extension)]):null,Div({className:"gh-tags"},[...showTags.map(tag=>Span({className:"gh-tag"},tag.data.tag_name)),allTags.length?Span({},sprintf("and %d more...",allTags.length)):null]),maybeCall(extra,item)])])};const ContactList=(contacts=[],{noContacts=()=>null,itemProps={}}={})=>{if(!contacts.length){return maybeCall(noContacts)}return Div({className:"contact-list"},contacts.map(contact=>ContactListItem(contact,maybeCall(itemProps,contact))))};const QuickSearch=({itemProps={},queryOverrides={}}={})=>{const State=Groundhogg.createState({search:"",searched:false,results:[],loaded:false});const fetchResults=async()=>{let results=await ContactsStore.fetchItems({search:State.search,orderby:"date_created",order:"DESC",limit:5,...queryOverrides});State.set({results:results,searched:true,loaded:true})};return Div({id:"quick-search-wrap"},morph=>{if(!State.loaded){fetchResults().then(morph)}const updateResults=debounce(async()=>{await fetchResults();morph()},300);return Fragment([Form({action:adminPageURL("gh_contacts")},[Input({type:"hidden",name:"page",value:"gh_contacts"}),Input({id:"quick-search-input",placeholder:__("Search by name or email...","groundhogg"),type:"search",name:"s",value:State.search,onInput:e=>{State.set({search:e.target.value});updateResults()}})]),State.loaded?null:Skeleton({},["full","full","full"]),State.results.length?ContactList(State.results,{itemProps:item=>({className:"contact-list-item clickable",onClick:e=>{window.open(item.admin,"_self")},...maybeCall(itemProps,item)})}):null,State.results.length===0&&State.searched?Pg({style:{textAlign:"center"}},__("No contacts found for the current search","groundhogg")):null])})};const Panel=({id,name,collapsed=false,hidden=false,onCollapse=id=>{}},content)=>{if(hidden){return null}return Div({id:`${id}-panel`,className:`gh-panel ${collapsed?"closed":""}`},[Div({className:`gh-panel-header`},[H2({},name),Button({className:"toggle-indicator",onClick:e=>{onCollapse(id)}})]),collapsed?null:maybeCall(content)])};const Panels=overrides=>({...Groundhogg.createRegistry({}),storagePrefix:"gh-panels",collapse(id){if(!this.isCollapsed(id)){this.toggleCollapse(id)}},expand(id){if(this.isCollapsed(id)){this.toggleCollapse(id)}},hide(id){if(!this.isHidden(id)){this.toggleHidden(id)}},show(id){if(this.isHidden(id)){this.toggleHidden(id)}},togglePanel(id,suffix){let panels=this.getPanelIds(suffix);if(panels.includes(id)){panels.splice(panels.indexOf(id),1)}else{panels.push(id)}localStorage.setItem(`${this.storagePrefix}-${suffix}`,JSON.stringify(panels))},toggleHidden(id){this.togglePanel(id,"hidden")},toggleCollapse(id){this.togglePanel(id,"collapsed")},getPanelIds(suffix){return JSON.parse(localStorage.getItem(`${this.storagePrefix}-${suffix}`))||[]},getHiddenPanelIds(){return this.getPanelIds("hidden")},getCollapsedPanelIds(){return this.getPanelIds("collapsed")},isHidden(id){return this.getHiddenPanelIds().includes(id)},isCollapsed(id){return this.getCollapsedPanelIds().includes(id)},PanelControls(){return Div({},[...this.map((item,id)=>Div({className:"display-flex gap-10",style:{marginBottom:"10px"}},[Toggle({checked:!this.isHidden(id),id:`toggle-${id}`,onChange:e=>{this.toggleHidden(id)}}),Label({for:`toggle-${id}`},item.name)]))])},Panel(id){let{content,...panel}=this.get(id);return Panel({id:id,...panel,collapsed:this.isCollapsed(id),hidden:this.isHidden(id),onCollapse:id=>{this.toggleCollapse(id);morphdom(document.getElementById(`${id}-panel`),this.Panel(id))}},content)},Panels(){return Div({className:"display-flex column gap-20",id:this.storagePrefix},this.keys().map(id=>this.Panel(id)))},...overrides});const Relationships=({title="",id,store,child_type="",parent_type="",renderItem=item=>{},onAddItem=(r,j)=>{}})=>{const rel_type_key=child_type?"child_type":"parent_type";const rel_type=child_type||parent_type;const rel_id_key=child_type?"child_id":"parent_id";const State=Groundhogg.createState({loaded:false,items:[]});const fetchRelationships=()=>store.fetchRelationships(id,{[rel_type_key]:rel_type}).then(items=>State.set({items:items,loaded:true}));const deleteRelationship=itemId=>store.deleteRelationships(id,{[rel_type_key]:rel_type,[rel_id_key]:itemId}).then(()=>State.set({items:State.items.filter(item=>item.ID!==itemId)}));const createRelationship=item=>store.createRelationships(id,{[rel_type_key]:rel_type,[rel_id_key]:item.ID}).then(()=>State.set({items:[...State.items,item]}));return Div({id:`${rel_type_key}-${rel_type}-rel-of-${id}`,className:`display-flex column relationship-editor ${rel_type_key}-${rel_type}`},morph=>{const handleDeleteRelationship=itemId=>deleteRelationship(itemId).then(morph);if(!State.loaded){fetchRelationships().then(morph);return Skeleton({},["full","full","full"])}const AddRelButton=()=>Button({id:`add-${rel_type_key}-${rel_type}-rel-for-${id}`,className:"gh-button secondary text icon",onClick:e=>{let promise=new Promise((resolve,reject)=>onAddItem(resolve,reject,State));promise.then(item=>createRelationship(item).then(morph))}},[Dashicon("plus-alt2"),ToolTip(__("Add relationship","groundhogg"),"left")]);return Fragment([title?Div({className:"space-between"},[H4({},title),AddRelButton()]):null,...State.items.map(item=>renderItem({...item,onDelete:handleDeleteRelationship})),title?null:Div({className:"display-flex flex-end"},AddRelButton())])})};const OwnerPicker=({id="select-owners",selected=[],onChange=ids=>{},allow0=true,itemDisplay=user=>user.data.display_name,multiple=true,...overrides})=>ItemPicker({id:`select-users`,noneSelected:__("Select a user...","groundhogg"),selected:selected.map(user_id=>{if(user_id==0&&allow0){return{id:0,text:__("The contact owner","groundhogg")}}return{id:user_id,text:itemDisplay(getOwner(user_id))}}),multiple:multiple,style:{flexGrow:1},isValidSelection:id=>id===0||getOwner(id),fetchOptions:search=>{search=new RegExp(search,"i");let options=Groundhogg.filters.owners.map(u=>({id:u.ID,text:itemDisplay(u)}));if(allow0){options.push({id:0,text:__("The contact owner","groundhogg")})}options=options.filter(({text})=>text.match(search));return Promise.resolve(options)},onChange:items=>{if(multiple){onChange(items.map(({id})=>id));return}onChange(items)},...overrides});function getClosestRelativeAncestor(element){let parent=element.parentElement;while(parent){if(window.getComputedStyle(parent).position==="relative"){return parent}parent=parent.parentElement}return null}const Tour=(steps,{onFinish=()=>{},beforeDismiss=({dismiss})=>dismiss(),onDismiss=()=>{},fixed=false})=>{const State=Groundhogg.createState({current:0,step:null,target:null,relative:null});const currentStep=()=>steps[State.current];const removeSteps=()=>{document.querySelectorAll(".tour-prompt-container").forEach(el=>el.remove());document.querySelectorAll(".tour-prompt").forEach(el=>el.remove());document.querySelectorAll(".tour-highlighted").forEach(el=>el.classList.remove("tour-highlighted"))};const remove=()=>{removeSteps();document.removeEventListener("resize",rePositionStep);document.removeEventListener("scroll",rePositionStep)};const dismiss=async()=>{remove();onDismiss()};const next=()=>{const{onNext=()=>{}}=currentStep();onNext();if(State.current+1>=steps.length){remove();onFinish(true);return}State.current++;showStep()};const prev=()=>{const{onPrev=()=>{}}=currentStep();onPrev();if(State.current<=0){return}State.current--;showStep()};const showStep=()=>{removeSteps();positionStep()};function rePositionStep(){let{position}=currentStep();let{target,relative,step,windowEl}=State;const targetPos=target.getBoundingClientRect();const relativePos=relative.getBoundingClientRect();const stepPos=step.getBoundingClientRect();const gap=20;if(fixed){windowEl.style.height=`${targetPos.height+gap*2}px`;windowEl.style.width=`${targetPos.width+gap*2}px`;windowEl.style.borderWidth=`${Math.round(targetPos.y)-gap}px ${Math.round(window.innerWidth-targetPos.x)-gap}px ${Math.round(window.innerHeight-targetPos.y)-gap}px ${Math.round(targetPos.x)-gap}px`;switch(position){case"right":step.style.left=`${targetPos.x+targetPos.width+gap}px`;step.style.top=`${targetPos.y}px`;break;case"left":step.style.left=`${targetPos.x-stepPos.width-gap}px`;step.style.top=`${targetPos.y}px`;break;case"above":step.style.left=`${targetPos.x}px`;step.style.top=`${targetPos.y-stepPos.height-gap}px`;break;case"below":step.style.left=`${targetPos.x}px`;step.style.top=`${targetPos.y+targetPos.height+gap}px`;break;case"below-left":step.style.left=`${targetPos.x+targetPos.width-stepPos.width}px`;step.style.top=`${targetPos.y+targetPos.height+gap}px`;break}return}switch(position){case"right":step.style.left=`${targetPos.right-relativePos.left+gap}px`;step.style.top=`${targetPos.top-relativePos.top}px`;break;case"left":step.style.left=`${targetPos.left-relativePos.left-stepPos.width-gap}px`;step.style.top=`${targetPos.top-relativePos.top}px`;break;case"above":step.style.left=`${targetPos.left-relativePos.left}px`;step.style.top=`${targetPos.top-relativePos.top-stepPos.height-gap}px`;break;case"below":step.style.left=`${targetPos.left-relativePos.left}px`;step.style.top=`${targetPos.bottom-relativePos.top+gap}px`;break;case"below-left":step.style.left=`${targetPos.right-relativePos.left-stepPos.width}px`;step.style.top=`${targetPos.bottom-relativePos.top+gap}px`;break}}function positionStep(){let tourEl=TourStep();let windowEl=tourEl.querySelector(".tour-window");let stepEl=tourEl.querySelector(".tour-prompt");let{target,relative,onInit=()=>{},onBefore=()=>{}}=currentStep();target=document.querySelector(target);if(!target){next();return}if(fixed){relative=document.body}else if(relative){relative=target.closest(relative)}else{relative=getClosestRelativeAncestor(target)}stepEl.style.position=fixed?"fixed":"absolute";if(fixed){relative.append(tourEl)}else{target.classList.add("tour-highlighted");relative.append(stepEl)}target.scrollIntoView({behavior:"instant",block:"center",inline:"center"});onBefore({next:next,prev:prev,target:target,relative:relative,step:stepEl,windowEl:windowEl,currentStep:currentStep});State.set({step:stepEl,windowEl:windowEl,target:target,relative:relative});rePositionStep();onInit({next:next,prev:prev,target:target,relative:relative,step:stepEl,windowEl:windowEl,currentStep:currentStep});stepEl.querySelector("#tour-next").focus()}const TourStep=()=>MakeEl.Div({className:"tour-prompt-container"},[fixed?MakeEl.Div({className:"tour-window"},[MakeEl.Div({className:"tour-window-shadow",onClick:next})]):null,MakeEl.Div({className:`tour-prompt ${currentStep().position}`,style:{padding:"10px",width:"200px"}},[MakeEl.Button({className:"dismiss",onClick:e=>{beforeDismiss({dismiss:dismiss,State:State})}},MakeEl.Dashicon("no-alt")),MakeEl.Div({},currentStep().prompt),MakeEl.Div({className:"display-flex flex-end gap-5 space-above-10"},[State.current>0?MakeEl.Button({id:"tour-prev",className:"gh-button small secondary text prev-step",onClick:()=>prev()},"Prev"):null,currentStep().showNext===false?null:MakeEl.Button({id:"tour-next",className:`gh-button small ${State.current<steps.length-1?"secondary":"primary"} next-step`,onClick:()=>next()},State.current<steps.length-1?"Next":"Finish")])])]);document.addEventListener("resize",rePositionStep);document.addEventListener("scroll",rePositionStep);positionStep()};Groundhogg.components={QuickSearch:QuickSearch,addContactModal:addContactModal,internalForm:internalForm,betterTagPicker:betterTagPicker,quickAddForm:quickAddForm,selectContactModal:selectContactModal,quickEditContactModal:quickEditContactModal,makeInput:makeInput,emailModal:emailModal,EmailTemplateModal:EmailTemplateModal,fileUploader:fileUploader,EmailPreview:EmailPreview,EmailPreviewModal:EmailPreviewModal,ImageInput:ImageInput,ImagePicker:ImagePicker,FeedbackModal:FeedbackModal,ContactList:ContactList,ContactListItem:ContactListItem,Panel:Panel,Panels:Panels,Relationships:Relationships,OwnerPicker:OwnerPicker,Tour:Tour}})(jQuery);
     218      `,onOpen:({close})=>{let file=null;let filesToUpload=[];let filesUploaded=[];let uploading=false;const pushFiles=()=>{renderUploadingFiles();file=filesToUpload.pop();if(!file){uploading=false;return}uploading=true;let fd=new FormData;fd.append(fileName,file,file.name);fd.append("gh_admin_ajax_nonce",Groundhogg.nonces._adminajax);fd.append("action",action);beforeUpload(fd);setTimeout(()=>{fetch(ajaxurl,{method:"POST",credentials:"same-origin",body:fd}).then(r=>{if(!r.ok){dialog({message:__("Something when wrong..."),type:"error"});return}return r.json()}).then(r=>{if(!r.success){dialog({message:r.data[0].message,type:"error"});pushFiles();return}onUpload(r,file);filesUploaded.unshift(file);renderUploadedFiles();pushFiles()})},2e3)};const renderUploadingFiles=()=>{$("#uploading-files").html(filesToUpload.map(f=>`<div class="file"><span class="hourglass">⌛</span> ${f.name}</div>`))};const renderUploadedFiles=()=>{$("#uploaded-files").html(filesUploaded.map(f=>`<div class="file">✅ ${f.name}</div>`))};const addFiles=files=>{filesToUpload.push(...files);if(!uploading){pushFiles()}};const $input=$("#upload-file-input");$input.on("change",e=>{addFiles(e.target.files)});$("#select-files").on("click",e=>{e.preventDefault();$input.click()});const $droppable=$(".droppable-handler");$droppable.on("dragover",e=>{e.preventDefault();$droppable.addClass("dragover")}).on("dragleave",e=>{$droppable.removeClass("dragover")}).on("drop",e=>{e.preventDefault();$droppable.removeClass("dragover");let{dataTransfer}=e.originalEvent;addFiles(dataTransfer.files)})}})};const EmailPreviewModal=async(emailId,{height=window.innerHeight*.85,width=900})=>{const{close}=loadingModal();let email;try{email=await EmailsStore.maybeFetchItem(emailId)}catch(err){close();throw err}const{from_avatar,from_email,from_name,subject,built:content}=email.context;close();return ModalFrame({frameAttributes:{className:"gh-modal-frame gh-email-preview-modal"}},({close})=>Div({style:{width:`${width}px`,height:`${height}px`}},EmailPreview({close:close,from_avatar:from_avatar,from_email:from_email,from_name:from_name,subject:subject,content:content})))};const EmailPreview=({close=false,from_avatar,from_email,from_name,subject,content})=>{return Div({className:"email-preview"},[Div({className:"from-preview display-flex gap-20 has-box-shadow"},[makeEl("img",{src:from_avatar,className:"from-avatar",height:40,width:40,style:{borderRadius:"50%"}}),Div({className:"subject-and-from"},[`<h2>${subject}</h2>`,`<span class="from-name">${from_name}</span> <span class="from-email">&lt;${from_email}&gt;</span>`]),close!==false?Button({className:"gh-button secondary icon text",style:{marginLeft:"auto"},onClick:close},Dashicon("no-alt")):null]),Iframe({id:"desktop-preview-iframe"},content)])};$(()=>{$(document).on("click","a.gh-email-preview",e=>{e.preventDefault();let emailId=e.currentTarget.dataset.id??e.currentTarget.closest("tr").id;EmailPreviewModal(parseInt(emailId),{})});window.addEventListener("hashchange",e=>{let hash=window.location.hash.replace("#","");if(hash.startsWith("gh-email-preview/")){let emailId=hash.replace("gh-email-preview/","");EmailPreviewModal(parseInt(emailId),{})}})});const ImagePicker=({multiple=false,title=__("Select a image to upload"),selectText=__("Use this image"),onChange=attachment=>{}})=>{let file_frame=wp.media({title:title,button:{text:selectText},multiple:multiple});file_frame.on("select",function(){let attachment=file_frame.state().get("selection").first().toJSON();onChange(attachment)});file_frame.open()};const ImageInput=({id,name="src",onChange,value=""})=>{const handleChange=(value,attachment=null)=>{onChange(value,attachment);morphdom(document.getElementById(id),ImageInput({id:id,name:name,onChange:onChange,value:value}))};return Div({id:id,className:"image-picker"},[value?Div({id:`${id}-preview`,className:"image-input-preview",style:{backgroundImage:`url(${value})`},onClick:e=>{e.preventDefault();ImagePicker({multiple:false,onChange:attachment=>handleChange(attachment.url,attachment)})}}):null,InputGroup([Input({type:"text",id:`${id}-src`,value:value,className:"control full-width",name:name,onChange:e=>{handleChange(e.target.value,null)}}),Button({id:`${id}-select`,className:"gh-button secondary icon",onClick:e=>{e.preventDefault();ImagePicker({multiple:false,onChange:attachment=>handleChange(attachment.url,attachment)})}},icons.image)])])};const FeedbackModal=({subject="",message="",onSubmit=r=>{}})=>{const State=Groundhogg.createState({subject:subject,message:message,submitting:false});ModalWithHeader({width:"400px",header:"Send Feedback"},({close,morph})=>Form({className:"display-flex column gap-5",onSubmit:e=>{e.preventDefault();State.set({submitting:true});morph();Groundhogg.api.ajax({action:"gh_plugin_feedback",subject:State.subject,message:State.message}).then(r=>{onSubmit(r);dialog({message:"Thanks for your feedback!"});close()});return false}},[Label({for:"feedback-subject"},["What feature are you submitting feedback for?"]),Input({id:"feedback-subject",value:State.subject,required:true,onInput:e=>State.set({subject:e.target.value})}),Div(),Label({for:"feedback-message"},["What is your feedback? Be as descriptive as possible."]),Textarea({id:"feedback-message",value:State.message,required:true,rows:4,onInput:e=>State.set({message:e.target.value})}),Button({className:"gh-button primary",type:"submit",disabled:State.submitting},"Send feedback"),Pg({},"Your email address will be collected to validate your feedback, but will not be used beyond that.")]))};$(document).on("click","a.feedback-modal",e=>{e.preventDefault();const{subject="",message=""}=e.currentTarget.dataset;FeedbackModal({subject:subject,message:message})});const ContactPhone=(icon,number,extension="")=>number?Span({className:"contact-phone"},[icon,An({href:`tel:${number}`},number),extension?Span({className:"ext"},` x${extension}`):null]):null;const ContactListItem=(item,{extra=item=>null,...props}={})=>{let allTags=jsonCopy(item.tags);let showTags=allTags.splice(0,10);const{ID}=item;const{full_name,gravatar,date_created,email}=item.data;const{primary_phone="",primary_phone_extension="",mobile_phone="",company_phone="",company_phone_extension=""}=item.meta;return Div({className:`contact-list-item`,id:`contact-list-item-${ID}`,dataId:ID,...props},[Div({className:"display-flex gap-10"},[Img({className:"avatar",src:gravatar,alt:"avatar"}),Div({className:"display-flex column"},[Div({},[makeEl("h4",{style:{margin:0}},full_name),Span({className:"subscribed"},`&nbsp;— ${sprintf(__("Subscribed %s"),`<abbr title="${formatDateTime(date_created)}">${sprintf(__("%s ago "),item.i18n.created)}</abbr>`)}`)]),Div({},[An({href:`mailto:${email}`},email),Span({},[" — ",Span({className:`gh-text ${item.is_marketable?"green":"red"}`},Groundhogg.filters.optin_status[item.data.optin_status])])])])]),Div({className:"show-on-hover"},[primary_phone||company_phone||mobile_phone?Div({className:"contact-phones"},[ContactPhone(icons.mobile,mobile_phone),ContactPhone(icons.phone,primary_phone,primary_phone_extension),ContactPhone(icons.phone,company_phone,company_phone_extension)]):null,Div({className:"gh-tags"},[...showTags.map(tag=>Span({className:"gh-tag"},tag.data.tag_name)),allTags.length?Span({},sprintf("and %d more...",allTags.length)):null]),maybeCall(extra,item)])])};const ContactList=(contacts=[],{noContacts=()=>null,itemProps={}}={})=>{if(!contacts.length){return maybeCall(noContacts)}return Div({className:"contact-list"},contacts.map(contact=>ContactListItem(contact,maybeCall(itemProps,contact))))};const QuickSearch=({itemProps={},queryOverrides={}}={})=>{const State=Groundhogg.createState({search:"",searched:false,results:[],loaded:false});const fetchResults=async()=>{let results=await ContactsStore.fetchItems({search:State.search,orderby:"date_created",order:"DESC",limit:5,...queryOverrides});State.set({results:results,searched:true,loaded:true})};return Div({id:"quick-search-wrap"},morph=>{if(!State.loaded){fetchResults().then(morph)}const updateResults=debounce(async()=>{await fetchResults();morph()},300);return Fragment([Form({action:adminPageURL("gh_contacts")},[Input({type:"hidden",name:"page",value:"gh_contacts"}),Input({id:"quick-search-input",placeholder:__("Search by name or email...","groundhogg"),type:"search",name:"s",value:State.search,onInput:e=>{State.set({search:e.target.value});updateResults()}})]),State.loaded?null:Skeleton({},["full","full","full"]),State.results.length?ContactList(State.results,{itemProps:item=>({className:"contact-list-item clickable",onClick:e=>{window.open(item.admin,"_self")},...maybeCall(itemProps,item)})}):null,State.results.length===0&&State.searched?Pg({style:{textAlign:"center"}},__("No contacts found for the current search","groundhogg")):null])})};const Panel=({id,name,collapsed=false,hidden=false,onCollapse=id=>{}},content)=>{if(hidden){return null}return Div({id:`${id}-panel`,className:`gh-panel ${collapsed?"closed":""}`},[Div({className:`gh-panel-header`},[H2({},name),Button({className:"toggle-indicator",onClick:e=>{onCollapse(id)}})]),collapsed?null:maybeCall(content)])};const Panels=overrides=>({...Groundhogg.createRegistry({}),storagePrefix:"gh-panels",collapse(id){if(!this.isCollapsed(id)){this.toggleCollapse(id)}},expand(id){if(this.isCollapsed(id)){this.toggleCollapse(id)}},hide(id){if(!this.isHidden(id)){this.toggleHidden(id)}},show(id){if(this.isHidden(id)){this.toggleHidden(id)}},togglePanel(id,suffix){let panels=this.getPanelIds(suffix);if(panels.includes(id)){panels.splice(panels.indexOf(id),1)}else{panels.push(id)}localStorage.setItem(`${this.storagePrefix}-${suffix}`,JSON.stringify(panels))},toggleHidden(id){this.togglePanel(id,"hidden")},toggleCollapse(id){this.togglePanel(id,"collapsed")},getPanelIds(suffix){return JSON.parse(localStorage.getItem(`${this.storagePrefix}-${suffix}`))||[]},getHiddenPanelIds(){return this.getPanelIds("hidden")},getCollapsedPanelIds(){return this.getPanelIds("collapsed")},isHidden(id){return this.getHiddenPanelIds().includes(id)},isCollapsed(id){return this.getCollapsedPanelIds().includes(id)},PanelControls(){return Div({},[...this.map((item,id)=>Div({className:"display-flex gap-10",style:{marginBottom:"10px"}},[Toggle({checked:!this.isHidden(id),id:`toggle-${id}`,onChange:e=>{this.toggleHidden(id)}}),Label({for:`toggle-${id}`},item.name)]))])},Panel(id){let{content,...panel}=this.get(id);return Panel({id:id,...panel,collapsed:this.isCollapsed(id),hidden:this.isHidden(id),onCollapse:id=>{this.toggleCollapse(id);morphdom(document.getElementById(`${id}-panel`),this.Panel(id))}},content)},Panels(){return Div({className:"display-flex column gap-20",id:this.storagePrefix},this.keys().map(id=>this.Panel(id)))},...overrides});const Relationships=({title="",id,store,child_type="",parent_type="",renderItem=item=>{},onAddItem=(r,j)=>{}})=>{const rel_type_key=child_type?"child_type":"parent_type";const rel_type=child_type||parent_type;const rel_id_key=child_type?"child_id":"parent_id";const State=Groundhogg.createState({loaded:false,items:[]});const fetchRelationships=()=>store.fetchRelationships(id,{[rel_type_key]:rel_type}).then(items=>State.set({items:items,loaded:true}));const deleteRelationship=itemId=>store.deleteRelationships(id,{[rel_type_key]:rel_type,[rel_id_key]:itemId}).then(()=>State.set({items:State.items.filter(item=>item.ID!==itemId)}));const createRelationship=item=>store.createRelationships(id,{[rel_type_key]:rel_type,[rel_id_key]:item.ID}).then(()=>State.set({items:[...State.items,item]}));return Div({id:`${rel_type_key}-${rel_type}-rel-of-${id}`,className:`display-flex column relationship-editor ${rel_type_key}-${rel_type}`},morph=>{const handleDeleteRelationship=itemId=>deleteRelationship(itemId).then(morph);if(!State.loaded){fetchRelationships().then(morph);return Skeleton({},["full","full","full"])}const AddRelButton=()=>Button({id:`add-${rel_type_key}-${rel_type}-rel-for-${id}`,className:"gh-button secondary text icon",onClick:e=>{let promise=new Promise((resolve,reject)=>onAddItem(resolve,reject,State));promise.then(item=>createRelationship(item).then(morph))}},[Dashicon("plus-alt2"),ToolTip(__("Add relationship","groundhogg"),"left")]);return Fragment([title?Div({className:"space-between"},[H4({},title),AddRelButton()]):null,...State.items.map(item=>renderItem({...item,onDelete:handleDeleteRelationship})),title?null:Div({className:"display-flex flex-end"},AddRelButton())])})};const OwnerPicker=({id="select-owners",selected=[],onChange=ids=>{},allow0=true,itemDisplay=user=>user.data.display_name,multiple=true,...overrides})=>ItemPicker({id:`select-users`,noneSelected:__("Select a user...","groundhogg"),selected:selected.map(user_id=>{if(user_id==0&&allow0){return{id:0,text:__("The contact owner","groundhogg")}}return{id:user_id,text:itemDisplay(getOwner(user_id))}}),multiple:multiple,style:{flexGrow:1},isValidSelection:id=>id===0||getOwner(id),fetchOptions:search=>{search=new RegExp(search,"i");let options=Groundhogg.filters.owners.map(u=>({id:u.ID,text:itemDisplay(u)}));if(allow0){options.push({id:0,text:__("The contact owner","groundhogg")})}options=options.filter(({text})=>text.match(search));return Promise.resolve(options)},onChange:items=>{if(multiple){onChange(items.map(({id})=>id));return}onChange(items)},...overrides});function getClosestRelativeAncestor(element){let parent=element.parentElement;while(parent){if(window.getComputedStyle(parent).position==="relative"){return parent}parent=parent.parentElement}return null}const Tour=(steps,{onFinish=()=>{},beforeDismiss=({dismiss})=>dismiss(),onDismiss=()=>{},fixed=false})=>{const State=Groundhogg.createState({current:0,step:null,target:null,relative:null});const currentStep=()=>steps[State.current];const removeSteps=()=>{document.querySelectorAll(".tour-prompt-container").forEach(el=>el.remove());document.querySelectorAll(".tour-prompt").forEach(el=>el.remove());document.querySelectorAll(".tour-highlighted").forEach(el=>el.classList.remove("tour-highlighted"))};const remove=()=>{removeSteps();document.removeEventListener("resize",rePositionStep);document.removeEventListener("scroll",rePositionStep)};const dismiss=async()=>{remove();onDismiss()};const next=()=>{const{onNext=()=>{}}=currentStep();onNext();if(State.current+1>=steps.length){remove();onFinish(true);return}State.current++;showStep()};const prev=()=>{const{onPrev=()=>{}}=currentStep();onPrev();if(State.current<=0){return}State.current--;showStep()};const showStep=()=>{removeSteps();positionStep()};function rePositionStep(){let{position}=currentStep();let{target,relative,step,windowEl}=State;const targetPos=target.getBoundingClientRect();const relativePos=relative.getBoundingClientRect();const stepPos=step.getBoundingClientRect();const gap=20;if(fixed){windowEl.style.height=`${targetPos.height+gap*2}px`;windowEl.style.width=`${targetPos.width+gap*2}px`;windowEl.style.borderWidth=`${Math.round(targetPos.y)-gap}px ${Math.round(window.innerWidth-targetPos.x)-gap}px ${Math.round(window.innerHeight-targetPos.y)-gap}px ${Math.round(targetPos.x)-gap}px`;switch(position){case"right":step.style.left=`${targetPos.x+targetPos.width+gap}px`;step.style.top=`${targetPos.y}px`;break;case"left":step.style.left=`${targetPos.x-stepPos.width-gap}px`;step.style.top=`${targetPos.y}px`;break;case"above":step.style.left=`${targetPos.x}px`;step.style.top=`${targetPos.y-stepPos.height-gap}px`;break;case"below":step.style.left=`${targetPos.x}px`;step.style.top=`${targetPos.y+targetPos.height+gap}px`;break;case"below-left":step.style.left=`${targetPos.x+targetPos.width-stepPos.width}px`;step.style.top=`${targetPos.y+targetPos.height+gap}px`;break}return}switch(position){case"right":step.style.left=`${targetPos.right-relativePos.left+gap}px`;step.style.top=`${targetPos.top-relativePos.top}px`;break;case"left":step.style.left=`${targetPos.left-relativePos.left-stepPos.width-gap}px`;step.style.top=`${targetPos.top-relativePos.top}px`;break;case"above":step.style.left=`${targetPos.left-relativePos.left}px`;step.style.top=`${targetPos.top-relativePos.top-stepPos.height-gap}px`;break;case"below":step.style.left=`${targetPos.left-relativePos.left}px`;step.style.top=`${targetPos.bottom-relativePos.top+gap}px`;break;case"below-left":step.style.left=`${targetPos.right-relativePos.left-stepPos.width}px`;step.style.top=`${targetPos.bottom-relativePos.top+gap}px`;break}}function positionStep(){let tourEl=TourStep();let windowEl=tourEl.querySelector(".tour-window");let stepEl=tourEl.querySelector(".tour-prompt");let{target,relative,onInit=()=>{},onBefore=()=>{}}=currentStep();target=document.querySelector(target);if(!target){next();return}if(fixed){relative=document.body}else if(relative){relative=target.closest(relative)}else{relative=getClosestRelativeAncestor(target)}stepEl.style.position=fixed?"fixed":"absolute";if(fixed){relative.append(tourEl)}else{target.classList.add("tour-highlighted");relative.append(stepEl)}target.scrollIntoView({behavior:"instant",block:"center",inline:"center"});onBefore({next:next,prev:prev,target:target,relative:relative,step:stepEl,windowEl:windowEl,currentStep:currentStep});State.set({step:stepEl,windowEl:windowEl,target:target,relative:relative});rePositionStep();onInit({next:next,prev:prev,target:target,relative:relative,step:stepEl,windowEl:windowEl,currentStep:currentStep});stepEl.querySelector("#tour-next").focus()}const TourStep=()=>MakeEl.Div({className:"tour-prompt-container"},[fixed?MakeEl.Div({className:"tour-window"},[MakeEl.Div({className:"tour-window-shadow",onClick:next})]):null,MakeEl.Div({className:`tour-prompt ${currentStep().position}`,style:{padding:"10px",width:"200px"}},[MakeEl.Button({className:"dismiss",onClick:e=>{beforeDismiss({dismiss:dismiss,State:State})}},MakeEl.Dashicon("no-alt")),MakeEl.Div({},currentStep().prompt),MakeEl.Div({className:"display-flex flex-end gap-5 space-above-10"},[State.current>0?MakeEl.Button({id:"tour-prev",className:"gh-button small secondary text prev-step",onClick:()=>prev()},"Prev"):null,currentStep().showNext===false?null:MakeEl.Button({id:"tour-next",className:`gh-button small ${State.current<steps.length-1?"secondary":"primary"} next-step`,onClick:()=>next()},State.current<steps.length-1?"Next":"Finish")])])]);document.addEventListener("resize",rePositionStep);document.addEventListener("scroll",rePositionStep);positionStep()};Groundhogg.components={QuickSearch:QuickSearch,addContactModal:addContactModal,internalForm:internalForm,betterTagPicker:betterTagPicker,quickAddForm:quickAddForm,selectContactModal:selectContactModal,quickEditContactModal:quickEditContactModal,makeInput:makeInput,emailModal:emailModal,EmailTemplateModal:EmailTemplateModal,fileUploader:fileUploader,EmailPreview:EmailPreview,EmailPreviewModal:EmailPreviewModal,ImageInput:ImageInput,ImagePicker:ImagePicker,FeedbackModal:FeedbackModal,ContactList:ContactList,ContactListItem:ContactListItem,Panel:Panel,Panels:Panels,Relationships:Relationships,OwnerPicker:OwnerPicker,Tour:Tour}})(jQuery);
  • groundhogg/trunk/assets/js/admin/emails/email-block-editor.js

    r3395861 r3458296  
    96439643    discord    : 'Discord',
    96449644    rumble     : 'Rumble',
     9645    bluesky    : 'Bluesky',
    96459646  }
    96469647
  • groundhogg/trunk/assets/js/admin/emails/email-block-editor.min.js

    r3395861 r3458296  
    195195          `]),`<!-- /wp:query -->`]).innerHTML},defaults:{layout:"cards",featured:true,excerpt:false,thumbnail:true,thumbnail_size:"thumbnail",columns:2,gap:20,cardStyle:{},headingStyle:fontDefaults({fontSize:24}),excerptStyle:fontDefaults({fontSize:16}),queryId:"",post_type:"post",number:5,offset:0}});const ChildBlocks=({children})=>Div({className:`children sortable-blocks ${children.length?"":"empty"}`,onCreate:el=>{makeSortable(el)}},[...children.map(b=>EditBlockWrapper(b))]);const QueryLoopContent=({DynamicContent,...block})=>{let dynamicContent=Div({},DynamicContent());let childBlockPlace=dynamicContent.querySelector(".replace-with-child-blocks");if(!childBlockPlace){return dynamicContent.firstElementChild}childBlockPlace.replaceWith(ChildBlocks(block));return Fragment([dynamicContent.firstElementChild])};const PostTagReference=[{tag:"the_title",desc:"The post title"},{tag:"the_excerpt",desc:"The post excerpt"},{tag:"the_url",desc:"The link to the post"},{tag:"the_thumbnail",desc:"The thumbnail image"},{tag:"the_thumbnail_url",desc:"The thumbnail image URL"},{tag:"the_content",desc:"The post content"},{tag:"the_id",desc:"The post ID"},{tag:"the_date",desc:"The post publish date"},{tag:"the_author",desc:"The post author"},{tag:"read_more",desc:'A "Read more" link to the post'}];registerDynamicBlock("queryloop","Query Loop",{svg:`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
    196196  <path fill="currentColor" d="M18 7a7.669 7.669 0 0 0-6 3.19A7.669 7.669 0 0 0 6 7c-3.687 0-5 2.583-5 5 0 3.687 2.583 5 5 5a7.669 7.669 0 0 0 6-3.19A7.669 7.669 0 0 0 18 17c2.417 0 5-1.313 5-5 0-2.417-1.313-5-5-5ZM6 15a2.689 2.689 0 0 1-3-3 2.689 2.689 0 0 1 3-3c2.579 0 4.225 2.065 4.837 3-.612.935-2.258 3-4.837 3Zm12 0c-2.579 0-4.225-2.065-4.837-3 .612-.935 2.258-3 4.837-3a2.689 2.689 0 0 1 3 3 2.689 2.689 0 0 1-3 3Z"/>
    197 </svg>`,attributes:{children:el=>{let blockTable=el.querySelector("table:not(.email-columns)");return parseBlocksFromTable(blockTable)}},controls:({gap=10,columns=2,thumbnail_size="post-thumbnail",updateBlock,...query})=>{return Fragment([ControlGroup({id:"queryloop-layout",name:"Layout"},[Control({label:"Columns"},NumberControl({id:"columns",className:"control-input",value:columns,step:1,onInput:e=>updateBlock({columns:e.target.value})})),Control({label:"Gap"},NumberControl({id:"column-gap",className:"control-input",value:gap,step:5,unit:"px",onInput:e=>updateBlock({gap:e.target.value})})),Control({label:"Thumbnail Size"},Select({id:"thumbnail-size",style:{width:"115px"},selected:thumbnail_size,options:imageSizes.map(size=>({value:size,text:size})),onChange:e=>updateBlock({thumbnail_size:e.target.value})}))]),QueryControls({updateBlock:updateBlock,...query}),ControlGroup({id:"queryloop-reference",name:"Reference"},[Pg({},"Use the below merge tags to merge post data within the query loop."),...PostTagReference.map(tag=>Div({className:"display-flex space-between"},[makeEl("code",{className:"copy-text"},`#${tag.tag}#`),Span({className:"tag-desc"},tag.desc)]))])])},edit:QueryLoopContent,html:({DynamicContent,...block})=>{if(isGeneratingHTML()){return renderBlocksHTML(block.children)}return QueryLoopContent({DynamicContent:DynamicContent,...block})},plainText:({children=[]})=>renderBlocksPlainText(children),defaults:{children:[createBlock("text",{content:`<p>#the_thumbnail#</p>\n<h2>#the_title#</h2>\n<p>#the_excerpt#</p>\n<p>#read_more#</p>`})],columns:2,layout:"grid",queryId:"",post_type:"post",number:6,offset:0,thumbnail_size:"post-thumbnail"}});const socialIcons={facebook:"Facebook",instagram:"Instagram",linkedin:"LinkedIn",pinterest:"Pinterest",reddit:"Reddit",threads:"Threads",tiktok:"TikTok",tumblr:"Tumblr",twitch:"Twitch",twitter:"𝕏",vimeo:"Vimeo",whatsapp:"WhatsApp",wordpress:"WordPress",youtube:"YouTube",github:"GitHub",truthsocial:"Truth Social",odysee:"Odysee",discord:"Discord",rumble:"Rumble"};const socialIconThemes={"brand-boxed":"Brand Colors Square","brand-circle":"Brand Colors Circular","brand-icons":"Brand Colors Icons","black-boxed":"Black Boxed","black-circle":"Black Circular","black-icons":"Black Icons","dark-grey-boxed":"Gray Boxed","dark-grey-circle":"Gray Circle","dark-grey-icons":"Gray Icons","grey-boxed":"Gray Boxed","grey-circle":"Gray Circle","grey-icons":"Gray Icons","white-boxed":"White Boxed","white-circle":"White Circular","white-icons":"White Icons"};const SocialIcon=(icon,theme="brand-circle",size=20)=>makeEl("img",{src:`${Groundhogg.assets.images}/social-icons/${theme}/${icon||"facebook"}.png`,alt:socialIcons[icon],height:size,width:size,style:{verticalAlign:"bottom"}});const SocialIconTheme=(theme,selected,updateBlock)=>{let themeIcons=["facebook","instagram","twitter"];let{use="global",socials=[]}=getActiveBlock();if(use==="global"&&globalSocials.length>=3){themeIcons=globalSocials.map(([social])=>social).slice(0,3)}else if(use==="custom"&&socials.length>=3){themeIcons=socials.map(([social])=>social).slice(0,3)}return Button({id:`select-${theme}`,title:socialIconThemes[theme],className:`gh-button ${theme===selected?"primary":"secondary text"} social-icon-theme ${theme}`,onClick:e=>updateBlock({theme:theme,morphControls:true})},themeIcons.map(icon=>SocialIcon(icon,theme,20)))};const SocialLinksRepeater=({socials,theme,onChange})=>InputRepeater({id:"social-links",rows:socials,cells:[({setValue,value,id,...props})=>Button({className:"gh-button grey icon",id:id,onClick:e=>{theme=hasActiveBlock()?getActiveBlock().theme:"brand-boxed";MiniModal({selector:`#${id}`},({close})=>Div({className:`display-grid social-icon-picker ${theme}`},[...Object.keys(socialIcons).map(social=>Button({title:socialIcons[social],id:`${id}-${social}`,className:"gh-button secondary text dashicon span-3",onClick:e=>{setValue(social);close()}},SocialIcon(social,theme)))]))}},SocialIcon(value||"facebook",theme)),({setValue,...props},[icon])=>Input({type:"url",placeholder:`https://${icon}.com/your-profile/`,...props})],sortable:true,onChange:onChange});registerBlock("social","Socials",{attributes:{size:el=>parseInt(el.querySelector("img")?.width),gap:el=>parseInt(el.querySelector("td.gap")?.width),theme:el=>el.querySelector("img")?.src.split("/").at(-2),socials:el=>Array.from(el.querySelectorAll("a")).map(el=>{let png=el.firstElementChild.src.split("/").at(-1);return[png.substr(0,png.indexOf(".png")),el.href]})},svg:`
     197</svg>`,attributes:{children:el=>{let blockTable=el.querySelector("table:not(.email-columns)");return parseBlocksFromTable(blockTable)}},controls:({gap=10,columns=2,thumbnail_size="post-thumbnail",updateBlock,...query})=>{return Fragment([ControlGroup({id:"queryloop-layout",name:"Layout"},[Control({label:"Columns"},NumberControl({id:"columns",className:"control-input",value:columns,step:1,onInput:e=>updateBlock({columns:e.target.value})})),Control({label:"Gap"},NumberControl({id:"column-gap",className:"control-input",value:gap,step:5,unit:"px",onInput:e=>updateBlock({gap:e.target.value})})),Control({label:"Thumbnail Size"},Select({id:"thumbnail-size",style:{width:"115px"},selected:thumbnail_size,options:imageSizes.map(size=>({value:size,text:size})),onChange:e=>updateBlock({thumbnail_size:e.target.value})}))]),QueryControls({updateBlock:updateBlock,...query}),ControlGroup({id:"queryloop-reference",name:"Reference"},[Pg({},"Use the below merge tags to merge post data within the query loop."),...PostTagReference.map(tag=>Div({className:"display-flex space-between"},[makeEl("code",{className:"copy-text"},`#${tag.tag}#`),Span({className:"tag-desc"},tag.desc)]))])])},edit:QueryLoopContent,html:({DynamicContent,...block})=>{if(isGeneratingHTML()){return renderBlocksHTML(block.children)}return QueryLoopContent({DynamicContent:DynamicContent,...block})},plainText:({children=[]})=>renderBlocksPlainText(children),defaults:{children:[createBlock("text",{content:`<p>#the_thumbnail#</p>\n<h2>#the_title#</h2>\n<p>#the_excerpt#</p>\n<p>#read_more#</p>`})],columns:2,layout:"grid",queryId:"",post_type:"post",number:6,offset:0,thumbnail_size:"post-thumbnail"}});const socialIcons={facebook:"Facebook",instagram:"Instagram",linkedin:"LinkedIn",pinterest:"Pinterest",reddit:"Reddit",threads:"Threads",tiktok:"TikTok",tumblr:"Tumblr",twitch:"Twitch",twitter:"𝕏",vimeo:"Vimeo",whatsapp:"WhatsApp",wordpress:"WordPress",youtube:"YouTube",github:"GitHub",truthsocial:"Truth Social",odysee:"Odysee",discord:"Discord",rumble:"Rumble",bluesky:"Bluesky"};const socialIconThemes={"brand-boxed":"Brand Colors Square","brand-circle":"Brand Colors Circular","brand-icons":"Brand Colors Icons","black-boxed":"Black Boxed","black-circle":"Black Circular","black-icons":"Black Icons","dark-grey-boxed":"Gray Boxed","dark-grey-circle":"Gray Circle","dark-grey-icons":"Gray Icons","grey-boxed":"Gray Boxed","grey-circle":"Gray Circle","grey-icons":"Gray Icons","white-boxed":"White Boxed","white-circle":"White Circular","white-icons":"White Icons"};const SocialIcon=(icon,theme="brand-circle",size=20)=>makeEl("img",{src:`${Groundhogg.assets.images}/social-icons/${theme}/${icon||"facebook"}.png`,alt:socialIcons[icon],height:size,width:size,style:{verticalAlign:"bottom"}});const SocialIconTheme=(theme,selected,updateBlock)=>{let themeIcons=["facebook","instagram","twitter"];let{use="global",socials=[]}=getActiveBlock();if(use==="global"&&globalSocials.length>=3){themeIcons=globalSocials.map(([social])=>social).slice(0,3)}else if(use==="custom"&&socials.length>=3){themeIcons=socials.map(([social])=>social).slice(0,3)}return Button({id:`select-${theme}`,title:socialIconThemes[theme],className:`gh-button ${theme===selected?"primary":"secondary text"} social-icon-theme ${theme}`,onClick:e=>updateBlock({theme:theme,morphControls:true})},themeIcons.map(icon=>SocialIcon(icon,theme,20)))};const SocialLinksRepeater=({socials,theme,onChange})=>InputRepeater({id:"social-links",rows:socials,cells:[({setValue,value,id,...props})=>Button({className:"gh-button grey icon",id:id,onClick:e=>{theme=hasActiveBlock()?getActiveBlock().theme:"brand-boxed";MiniModal({selector:`#${id}`},({close})=>Div({className:`display-grid social-icon-picker ${theme}`},[...Object.keys(socialIcons).map(social=>Button({title:socialIcons[social],id:`${id}-${social}`,className:"gh-button secondary text dashicon span-3",onClick:e=>{setValue(social);close()}},SocialIcon(social,theme)))]))}},SocialIcon(value||"facebook",theme)),({setValue,...props},[icon])=>Input({type:"url",placeholder:`https://${icon}.com/your-profile/`,...props})],sortable:true,onChange:onChange});registerBlock("social","Socials",{attributes:{size:el=>parseInt(el.querySelector("img")?.width),gap:el=>parseInt(el.querySelector("td.gap")?.width),theme:el=>el.querySelector("img")?.src.split("/").at(-2),socials:el=>Array.from(el.querySelectorAll("a")).map(el=>{let png=el.firstElementChild.src.split("/").at(-1);return[png.substr(0,png.indexOf(".png")),el.href]})},svg:`
    198198        <svg viewBox="-33 0 512 512.001" xmlns="http://www.w3.org/2000/svg">
    199199            <path fill="currentColor"
  • groundhogg/trunk/groundhogg.php

    r3442828 r3458296  
    44 * Plugin URI: https://www.groundhogg.io/?utm_source=wp-plugins&utm_campaign=plugin-uri&utm_medium=wp-dash
    55 * Description: CRM and marketing automation for WordPress
    6  * Version: 4.2.11
     6 * Version: 4.2.12
    77 * Author: Groundhogg Inc.
    88 * Author URI: https://www.groundhogg.io/?utm_source=wp-plugins&utm_campaign=author-uri&utm_medium=wp-dash
     
    2525if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
    2626
    27 define( 'GROUNDHOGG_VERSION', '4.2.11' );
    28 define( 'GROUNDHOGG_PREVIOUS_STABLE_VERSION', '4.2.10' );
     27define( 'GROUNDHOGG_VERSION', '4.2.12' );
     28define( 'GROUNDHOGG_PREVIOUS_STABLE_VERSION', '4.2.11' );
    2929
    3030define( 'GROUNDHOGG__FILE__', __FILE__ );
  • groundhogg/trunk/includes/classes/funnel.php

    r3343709 r3458296  
    642642        }
    643643
    644         $last_changed = db()->steps->cache_get_last_changed();
    645         $cache_key    = "$this->ID:steps:$last_changed:" . md5serialize( $query );
    646         $steps        = wp_cache_get( $cache_key, db()->steps->get_cache_group(), false, $found );
    647 
    648         // make sure all items in array are also steps
    649         if ( $found && is_array( $steps ) && array_all( $steps, function ( $step ) {
    650                 return is_a( $step, Step::class );
    651             } ) ) {
    652 
    653             return $steps;
    654         }
     644//      $last_changed = db()->steps->cache_get_last_changed();
     645//      $cache_key    = "$this->ID:steps:$last_changed:" . md5serialize( $query );
     646//      $steps        = wp_cache_get( $cache_key, db()->steps->get_cache_group(), false, $found );
     647//
     648//        // make sure all items in array are also steps
     649//      if ( $found && is_array( $steps ) && array_all( $steps, function ( $step ) {
     650//              return is_a( $step, Step::class );
     651//          } ) ) {
     652//
     653//          return $steps;
     654//      }
    655655
    656656        $steps = $this->get_steps_db()->query( $query );
     
    674674        }
    675675
    676         wp_cache_set( $cache_key, $steps, db()->steps->get_cache_group(), MINUTE_IN_SECONDS );
     676//      wp_cache_set( $cache_key, $steps, db()->steps->get_cache_group(), MINUTE_IN_SECONDS );
    677677
    678678        return $steps;
  • groundhogg/trunk/includes/form/form-v2.php

    r3400645 r3458296  
    19031903    protected $hidden_fields = [];
    19041904
     1905    public function is_turnstile_enabled() {
     1906        $turnstile = get_array_var( $this->get_cleaned_json_config(), 'turnstile', [] );
     1907        return isset_not_empty( $turnstile, 'enabled' ) && is_recaptcha_enabled();
     1908    }
     1909
     1910    public function is_recaptcha_enabled() {
     1911        $recaptcha = get_array_var( $this->get_cleaned_json_config(), 'recaptcha', [] );
     1912        return isset_not_empty( $recaptcha, 'enabled' ) && is_recaptcha_enabled();
     1913    }
     1914
     1915    /**
     1916     * Get a cleaned assoc array of the form config
     1917     *
     1918     * @return array
     1919     */
     1920    private function get_cleaned_json_config() {
     1921        $config = $this->get_meta( 'form' );
     1922        // encode and decode to fix potential mutation errors when importing/exporting
     1923        return json_decode( wp_json_encode( $config ), true );
     1924    }
     1925
    19051926    /**
    19061927     * Get the HTML For the fields
     
    19091930     */
    19101931    function get_field_html() {
    1911 
    1912         $config = $this->get_meta( 'form' );
    1913 
    1914         $config = json_decode( wp_json_encode( $config ), true );
    1915 
     1932        $config = $this->get_cleaned_json_config();
    19161933        $fields = get_array_var( $config, 'fields', [] );
    19171934
     
    22032220     */
    22042221    public function get_fields() {
    2205         $config = json_decode( wp_json_encode( $this->get_meta( 'form' ) ), true );
     2222        $config = $this->get_cleaned_json_config();
    22062223
    22072224        if ( ! is_array( $config ) || ! isset( $config['fields'] ) ) {
     
    22292246
    22302247        // Ensure array and not stdClass
    2231         $config    = json_decode( wp_json_encode( $this->get_meta( 'form' ) ), true );
     2248        $config    = $this->get_cleaned_json_config();
    22322249        $fields    = $config['fields'];
    2233         $recaptcha = $config['recaptcha'];
    2234         $turnstile = $config['turnstile'];
    2235 
    2236         if ( $recaptcha['enabled'] ) {
    2237             $fields[] = $recaptcha;
    2238         }
    2239 
    2240         if ( $turnstile['enabled'] ) {
    2241             $fields[] = $turnstile;
     2250
     2251        // add the recaptcha to fields array for validation
     2252        if ( isset( $config[ 'recaptcha' ] ) &&  $config[ 'recaptcha' ]['enabled'] ){
     2253            $fields[] = $config['recaptcha'];
     2254        }
     2255
     2256        // add the turnstile to fields array for validation
     2257        if ( isset( $config[ 'turnstile' ] ) &&  $config[ 'turnstile' ]['enabled'] ){
     2258            $fields[] = $config['turnstile'];
    22422259        }
    22432260
  • groundhogg/trunk/includes/functions.php

    r3442828 r3458296  
    25902590 * @return false|Contact
    25912591 */
    2592 function update_contact_with_map( $contact, array $fields, array $map = [], $submission = [] ) {
     2592function update_contact_with_map( mixed $contact, array $fields, array $map = [], array $submission = [] ) {
    25932593    return generate_contact_with_map( $fields, $map, $submission, $contact );
    25942594}
     
    25992599 * @throws \Exception
    26002600 *
    2601  * @param              $fields     array the raw data from the source
    2602  * @param              $map        array map of field_ids to contact keys
     2601 * @param  array       $fields    the raw data from the source
     2602 * @param  array       $map        map of field_ids to contact keys
    26032603 * @param array        $submission settings for the submission
    26042604 * @param null|Contact $contact    an existing contact record to modify
     
    26062606 * @return Contact|false
    26072607 */
    2608 function generate_contact_with_map( $fields, $map = [], $submission = [], $contact = null ) {
     2608function generate_contact_with_map( array $fields, array $map = [], array $submission = [], mixed $contact = null ) {
    26092609
    26102610    if ( empty( $map ) ) {
     
    38623862 *
    38633863 * @param string $call_name   the name you wish to call
    3864  * @param string $id_or_email id or email of the contact
     3864 * @param string|int|Contact $id_or_email id or email of the contact
    38653865 * @param bool   $by_user_id  whether the ID is the ID of a WP user
    38663866 */
     
    82738273 */
    82748274function verify_admin_ajax_nonce() {
    8275     return wp_verify_nonce( get_request_var( 'gh_admin_ajax_nonce' ), 'admin_ajax' );
     8275    return check_ajax_referer( 'admin_ajax', 'gh_admin_ajax_nonce', false );
    82768276}
    82778277
Note: See TracChangeset for help on using the changeset viewer.