From 8004f4c96d88977590860cace5fb77aa1f2a600e Mon Sep 17 00:00:00 2001 From: Jan Henk Hazelaar Date: Mon, 13 Jul 2026 19:41:01 +0200 Subject: [PATCH 1/3] Memoize MailerLite group lookups MailerLiteGroups fetched a group from the API for every selected value it resolved and let API errors bubble into the Control Panel. It now reuses a request-memoized group list and swallows API failures, exactly like MailerLiteFields already did. Also drops the canCreate, canEdit, canSearch and statusIcons overrides from MailerLiteFields, which only restated the Relationship base class defaults. Changelog: performance --- src/Fieldtypes/MailerLiteFields.php | 8 -- src/Fieldtypes/MailerLiteGroups.php | 76 +++++++++---------- .../Feature/MailerLiteGroupsFieldtypeTest.php | 13 ++++ 3 files changed, 48 insertions(+), 49 deletions(-) create mode 100644 tests/Feature/MailerLiteGroupsFieldtypeTest.php diff --git a/src/Fieldtypes/MailerLiteFields.php b/src/Fieldtypes/MailerLiteFields.php index 42fe375..025ad22 100644 --- a/src/Fieldtypes/MailerLiteFields.php +++ b/src/Fieldtypes/MailerLiteFields.php @@ -13,14 +13,6 @@ class MailerLiteFields extends Relationship protected $indexComponent = 'text'; - protected $canCreate = false; - - protected $canEdit = false; - - protected $canSearch = false; - - protected $statusIcons = false; - /** @var array> */ private static array $cache = []; diff --git a/src/Fieldtypes/MailerLiteGroups.php b/src/Fieldtypes/MailerLiteGroups.php index 78414c5..bc78dc9 100644 --- a/src/Fieldtypes/MailerLiteGroups.php +++ b/src/Fieldtypes/MailerLiteGroups.php @@ -13,49 +13,17 @@ class MailerLiteGroups extends Relationship protected $indexComponent = 'text'; + /** @var array> */ + private static array $cache = []; + protected function toItemArray($id) { - $mailerLite = $this->mailerLite(); - - if (! $mailerLite) { - return $this->invalidItemArray($id); - } - - $response = $mailerLite->groups->find($id); - - if (! isset($response['body']['data'])) { - return $this->invalidItemArray($id); - } - - $group = $response['body']['data']; - - return [ - 'id' => $group['id'], - 'title' => $group['name'], - ]; + return collect($this->groups())->firstWhere('id', $id) ?? $this->invalidItemArray($id); } public function getIndexItems($request) { - $mailerLite = $this->mailerLite(); - - if (! $mailerLite) { - return collect(); - } - - $response = $mailerLite->groups->get([ - 'limit' => 100, - 'sort' => 'name', - ]); - - if (! isset($response['body']['data'])) { - return collect(); - } - - return collect($response['body']['data'])->map(fn (array $group) => [ - 'id' => $group['id'], - 'title' => $group['name'], - ]); + return collect($this->groups()); } protected function getColumns() @@ -78,14 +46,40 @@ public function preProcessIndex($data) })->join(', '); } - private function mailerLite(): ?MailerLite + /** + * The selectable MailerLite groups, memoized per request so resolving + * selected values does not hit the API once per value. + * + * @return array + */ + private function groups(): array { $apiKey = Addon::get('concept7/statamic-mailerlite')->setting('api_key'); - if (! $apiKey) { - return null; + if (blank($apiKey)) { + return []; + } + + $cacheKey = hash('sha256', $apiKey); + + if (isset(self::$cache[$cacheKey])) { + return self::$cache[$cacheKey]; } - return new MailerLite(['api_key' => $apiKey]); + return self::$cache[$cacheKey] = rescue(function () use ($apiKey): array { + $response = (new MailerLite(['api_key' => $apiKey])) + ->groups + ->get([ + 'limit' => 100, + 'sort' => 'name', + ]); + + return collect($response['body']['data'] ?? []) + ->map(fn (array $group): array => [ + 'id' => $group['id'], + 'title' => $group['name'], + ]) + ->all(); + }, [], report: false); } } diff --git a/tests/Feature/MailerLiteGroupsFieldtypeTest.php b/tests/Feature/MailerLiteGroupsFieldtypeTest.php new file mode 100644 index 0000000..32f8e21 --- /dev/null +++ b/tests/Feature/MailerLiteGroupsFieldtypeTest.php @@ -0,0 +1,13 @@ +shouldReceive('setting')->with('api_key')->andReturn(null); + + Addon::shouldReceive('get')->with('concept7/statamic-mailerlite')->andReturn($addon); + + expect((new MailerLiteGroups)->getIndexItems(request()))->toBeEmpty(); +}); From a94ea13132239ff5937cda13b58b8ba36785e154 Mon Sep 17 00:00:00 2001 From: Jan Henk Hazelaar Date: Mon, 13 Jul 2026 19:45:20 +0200 Subject: [PATCH 2/3] Rename MailerLiteFormFields to FormFields The fieldtype lists the Statamic form's own fields, not MailerLite data, so the MailerLite prefix was misleading. The handle changes from mailer_lite_form_fields to form_fields (matching the rad-pack Mailchimp convention); it only exists in runtime blueprint registration, so no stored form config is affected. Changelog: changed --- package-lock.json | 2 +- .../build/assets/{addon-Dnt1-tBd.js => addon-54LLqdMz.js} | 2 +- resources/dist/build/manifest.json | 2 +- resources/js/addon.js | 4 ++-- ...iteFormFieldsFieldtype.vue => FormFieldsFieldtype.vue} | 0 .../{MailerLiteFormFields.php => FormFields.php} | 2 +- src/StatamicMailerLiteServiceProvider.php | 2 +- ...ieldsFieldtypeTest.php => FormFieldsFieldtypeTest.php} | 8 ++++---- tests/Feature/MailerLiteConfigFieldsTest.php | 2 +- 9 files changed, 12 insertions(+), 12 deletions(-) rename resources/dist/build/assets/{addon-Dnt1-tBd.js => addon-54LLqdMz.js} (61%) rename resources/js/components/fieldtypes/{MailerLiteFormFieldsFieldtype.vue => FormFieldsFieldtype.vue} (100%) rename src/Fieldtypes/{MailerLiteFormFields.php => FormFields.php} (96%) rename tests/Feature/{MailerLiteFormFieldsFieldtypeTest.php => FormFieldsFieldtypeTest.php} (81%) diff --git a/package-lock.json b/package-lock.json index e004f98..1f46222 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "statamic-mailerlite", + "name": "concept7-statamic-mailerlite", "lockfileVersion": 3, "requires": true, "packages": { diff --git a/resources/dist/build/assets/addon-Dnt1-tBd.js b/resources/dist/build/assets/addon-54LLqdMz.js similarity index 61% rename from resources/dist/build/assets/addon-Dnt1-tBd.js rename to resources/dist/build/assets/addon-54LLqdMz.js index da23103..78be2d5 100644 --- a/resources/dist/build/assets/addon-Dnt1-tBd.js +++ b/resources/dist/build/assets/addon-54LLqdMz.js @@ -1 +1 @@ -const c=window.Vue,{BaseTransition:g,BaseTransitionPropsValidators:h,Comment:T,DeprecationTypes:f,EffectScope:v,ErrorCodes:b,ErrorTypeStrings:P,Fragment:R,KeepAlive:y,ReactiveEffect:w,Static:x,Suspense:M,Teleport:I,Text:F,TrackOpTypes:E,Transition:D,TransitionGroup:H,TriggerOpTypes:L,VueElement:k,__esModule:A,assertNumber:V,callWithAsyncErrorHandling:_,callWithErrorHandling:B,camelize:O,capitalize:z,cloneVNode:N,compatUtils:G,compile:U,computed:K,createApp:W,createBlock:p,createCommentVNode:j,createElementBlock:q,createElementVNode:$,createHydrationRenderer:Q,createPropsRestProxy:J,createRenderer:X,createSSRApp:Y,createSlots:Z,createStaticVNode:ee,createTextVNode:te,createVNode:oe,customRef:re,defineAsyncComponent:ie,defineComponent:ne,defineCustomElement:ae,defineEmits:se,defineExpose:le,defineModel:de,defineOptions:ce,defineProps:pe,defineSSRCustomElement:ue,defineSlots:me,devtools:Ce,effect:Se,effectScope:ge,getCurrentInstance:he,getCurrentScope:Te,getCurrentWatcher:fe,getTransitionRawChildren:ve,guardReactiveProps:be,h:Pe,handleError:Re,hasInjectionContext:ye,hydrate:we,hydrateOnIdle:xe,hydrateOnInteraction:Me,hydrateOnMediaQuery:Ie,hydrateOnVisible:Fe,initCustomFormatter:Ee,initDirectivesForSSR:De,inject:He,isMemoSame:Le,isProxy:ke,isReactive:Ae,isReadonly:Ve,isRef:_e,isRuntimeOnly:Be,isShallow:Oe,isVNode:ze,markRaw:Ne,mergeDefaults:Ge,mergeModels:Ue,mergeProps:Ke,nextTick:We,nodeOps:je,normalizeClass:qe,normalizeProps:$e,normalizeStyle:Qe,onActivated:Je,onBeforeMount:Xe,onBeforeUnmount:Ye,onBeforeUpdate:Ze,onDeactivated:et,onErrorCaptured:tt,onMounted:ot,onRenderTracked:rt,onRenderTriggered:it,onScopeDispose:nt,onServerPrefetch:at,onUnmounted:st,onUpdated:lt,onWatcherCleanup:dt,openBlock:u,patchProp:ct,popScopeId:pt,provide:ut,proxyRefs:mt,pushScopeId:Ct,queuePostFlushCb:St,reactive:gt,readonly:ht,ref:Tt,registerRuntimeCompiler:ft,render:vt,renderList:bt,renderSlot:Pt,resolveComponent:Rt,resolveDirective:yt,resolveDynamicComponent:wt,resolveFilter:xt,resolveTransitionHooks:Mt,setBlockTracking:It,setDevtoolsHook:Ft,setTransitionHooks:Et,shallowReactive:Dt,shallowReadonly:Ht,shallowRef:Lt,ssrContextKey:kt,ssrUtils:At,stop:Vt,toDisplayString:_t,toHandlerKey:Bt,toHandlers:Ot,toRaw:zt,toRef:Nt,toRefs:Gt,toValue:Ut,transformVNodeArgs:Kt,triggerRef:Wt,unref:o,useAttrs:jt,useCssModule:qt,useCssVars:$t,useHost:Qt,useId:Jt,useModel:Xt,useSSRContext:Yt,useShadowRoot:Zt,useSlots:eo,useTemplateRef:to,useTransitionState:oo,vModelCheckbox:ro,vModelDynamic:io,vModelRadio:no,vModelSelect:ao,vModelText:so,vShow:lo,version:co,warn:po,watch:uo,watchEffect:mo,watchPostEffect:Co,watchSyncEffect:So,withAsyncContext:go,withCtx:ho,withDefaults:To,withDirectives:fo,withKeys:vo,withMemo:bo,withModifiers:Po,withScopeId:Ro}=c,{Fieldtype:e,IndexFieldtype:yo,FieldtypeMixin:wo,HasActionsMixin:xo,HasInputOptionsMixin:Mo,HasPreferencesMixin:Io,IndexFieldtypeMixin:Fo,InlineEditForm:Eo,DateFormatter:Do,NumberFormatter:Ho,ItemActions:Lo,RelatedItem:ko,RestoreRevision:Ao,RevisionHistory:Vo,RevisionPreview:_o,SaveButtonOptions:Bo,SortableList:Oo,requireElevatedSession:zo,requireElevatedSessionIf:No,clone:Go,debounce:Uo,deepClone:Ko,resetValuesFromResponse:Wo}=__STATAMIC__.core,{Alert:jo,AuthCard:qo,Avatar:$o,Badge:Qo,Button:Jo,ButtonGroup:Xo,Calendar:Yo,Card:Zo,CardList:er,CardListItem:tr,CardPanel:or,CharacterCounter:rr,Checkbox:ir,CheckboxGroup:nr,CodeEditor:ar,Combobox:m,CommandPaletteItem:sr,ConfirmationModal:lr,Context:dr,ContextFooter:cr,ContextHeader:pr,ContextItem:ur,ContextLabel:mr,ContextMenu:Cr,ContextSeparator:Sr,CreateForm:gr,DatePicker:hr,DateRangePicker:Tr,Description:fr,DocsCallout:vr,DragHandle:br,Dropdown:Pr,DropdownItem:Rr,DropdownLabel:yr,DropdownMenu:wr,DropdownSeparator:xr,DropdownFooter:Mr,DropdownHeader:Ir,Editable:Fr,ErrorMessage:Er,EmptyStateItem:Dr,EmptyStateMenu:Hr,Field:Lr,Header:kr,Heading:Ar,HoverCard:Vr,Icon:_r,Input:Br,InputGroup:Or,InputGroupAppend:zr,InputGroupPrepend:Nr,Label:Gr,Listing:Ur,ListingCustomizeColumns:Kr,ListingFilters:Wr,ListingHeaderCell:jr,ListingPagination:qr,ListingPresets:$r,ListingPresetTrigger:Qr,ListingRowActions:Jr,ListingSearch:Xr,ListingTable:Yr,ListingTableBody:Zr,ListingTableHead:ei,ListingToggleAll:ti,LivePreview:oi,LivePreviewPopout:ri,MiddleEllipsis:ii,Modal:ni,ModalClose:ai,ModalTitle:si,Pagination:li,Panel:di,PanelFooter:ci,PanelHeader:pi,Popover:ui,PublishComponents:mi,PublishContainer:Ci,publishContextKey:Si,injectPublishContext:gi,PublishField:hi,PublishFields:Ti,PublishFieldsProvider:fi,PublishForm:vi,PublishLocalizations:bi,PublishSections:Pi,PublishTabs:Ri,Radio:yi,RadioGroup:wi,Select:xi,Separator:Mi,Slider:Ii,Skeleton:Fi,SplitterGroup:Ei,SplitterPanel:Di,SplitterResizeHandle:Hi,StatusIndicator:Li,Subheading:ki,Switch:Ai,TabContent:Vi,Stack:_i,StackClose:Bi,StackHeader:Oi,StackFooter:zi,StackContent:Ni,Table:Gi,TableCell:Ui,TableColumn:Ki,TableColumns:Wi,TableRow:ji,TableRows:qi,TabList:$i,TabProvider:Qi,Tabs:Ji,TabTrigger:Xi,Text:Yi,Textarea:Zi,TimePicker:en,TimezoneHoverCard:tn,Timezones:on,ToggleGroup:rn,ToggleItem:nn,Widget:an,registerIconSet:sn,registerIconSetFromStrings:ln}=__STATAMIC__.ui,C={__name:"MailerLiteFormFieldsFieldtype",props:e.props,emits:e.emits,setup(r,{expose:i,emit:n}){const a=n,s=r,{expose:l,update:d}=e.use(a,s);return i(l),(t,S)=>(u(),p(o(m),{class:"w-full",clearable:"",searchable:"","model-value":t.value,options:t.meta.options,"option-label":"label","option-value":"value","onUpdate:modelValue":o(d)},null,8,["model-value","options","onUpdate:modelValue"]))}};Statamic.booting(()=>{Statamic.$components.register("mailer_lite_form_fields-fieldtype",C)}); +const c=window.Vue,{BaseTransition:g,BaseTransitionPropsValidators:h,Comment:T,DeprecationTypes:f,EffectScope:v,ErrorCodes:b,ErrorTypeStrings:P,Fragment:R,KeepAlive:y,ReactiveEffect:w,Static:x,Suspense:M,Teleport:I,Text:F,TrackOpTypes:E,Transition:D,TransitionGroup:H,TriggerOpTypes:k,VueElement:L,__esModule:A,assertNumber:V,callWithAsyncErrorHandling:_,callWithErrorHandling:B,camelize:O,capitalize:z,cloneVNode:N,compatUtils:G,compile:U,computed:K,createApp:W,createBlock:p,createCommentVNode:j,createElementBlock:q,createElementVNode:$,createHydrationRenderer:Q,createPropsRestProxy:J,createRenderer:X,createSSRApp:Y,createSlots:Z,createStaticVNode:ee,createTextVNode:te,createVNode:oe,customRef:re,defineAsyncComponent:ne,defineComponent:ie,defineCustomElement:ae,defineEmits:se,defineExpose:le,defineModel:de,defineOptions:ce,defineProps:pe,defineSSRCustomElement:ue,defineSlots:me,devtools:Ce,effect:Se,effectScope:ge,getCurrentInstance:he,getCurrentScope:Te,getCurrentWatcher:fe,getTransitionRawChildren:ve,guardReactiveProps:be,h:Pe,handleError:Re,hasInjectionContext:ye,hydrate:we,hydrateOnIdle:xe,hydrateOnInteraction:Me,hydrateOnMediaQuery:Ie,hydrateOnVisible:Fe,initCustomFormatter:Ee,initDirectivesForSSR:De,inject:He,isMemoSame:ke,isProxy:Le,isReactive:Ae,isReadonly:Ve,isRef:_e,isRuntimeOnly:Be,isShallow:Oe,isVNode:ze,markRaw:Ne,mergeDefaults:Ge,mergeModels:Ue,mergeProps:Ke,nextTick:We,nodeOps:je,normalizeClass:qe,normalizeProps:$e,normalizeStyle:Qe,onActivated:Je,onBeforeMount:Xe,onBeforeUnmount:Ye,onBeforeUpdate:Ze,onDeactivated:et,onErrorCaptured:tt,onMounted:ot,onRenderTracked:rt,onRenderTriggered:nt,onScopeDispose:it,onServerPrefetch:at,onUnmounted:st,onUpdated:lt,onWatcherCleanup:dt,openBlock:u,patchProp:ct,popScopeId:pt,provide:ut,proxyRefs:mt,pushScopeId:Ct,queuePostFlushCb:St,reactive:gt,readonly:ht,ref:Tt,registerRuntimeCompiler:ft,render:vt,renderList:bt,renderSlot:Pt,resolveComponent:Rt,resolveDirective:yt,resolveDynamicComponent:wt,resolveFilter:xt,resolveTransitionHooks:Mt,setBlockTracking:It,setDevtoolsHook:Ft,setTransitionHooks:Et,shallowReactive:Dt,shallowReadonly:Ht,shallowRef:kt,ssrContextKey:Lt,ssrUtils:At,stop:Vt,toDisplayString:_t,toHandlerKey:Bt,toHandlers:Ot,toRaw:zt,toRef:Nt,toRefs:Gt,toValue:Ut,transformVNodeArgs:Kt,triggerRef:Wt,unref:o,useAttrs:jt,useCssModule:qt,useCssVars:$t,useHost:Qt,useId:Jt,useModel:Xt,useSSRContext:Yt,useShadowRoot:Zt,useSlots:eo,useTemplateRef:to,useTransitionState:oo,vModelCheckbox:ro,vModelDynamic:no,vModelRadio:io,vModelSelect:ao,vModelText:so,vShow:lo,version:co,warn:po,watch:uo,watchEffect:mo,watchPostEffect:Co,watchSyncEffect:So,withAsyncContext:go,withCtx:ho,withDefaults:To,withDirectives:fo,withKeys:vo,withMemo:bo,withModifiers:Po,withScopeId:Ro}=c,{Fieldtype:e,IndexFieldtype:yo,FieldtypeMixin:wo,HasActionsMixin:xo,HasInputOptionsMixin:Mo,HasPreferencesMixin:Io,IndexFieldtypeMixin:Fo,InlineEditForm:Eo,DateFormatter:Do,NumberFormatter:Ho,ItemActions:ko,RelatedItem:Lo,RestoreRevision:Ao,RevisionHistory:Vo,RevisionPreview:_o,SaveButtonOptions:Bo,SortableList:Oo,requireElevatedSession:zo,requireElevatedSessionIf:No,clone:Go,debounce:Uo,deepClone:Ko,resetValuesFromResponse:Wo}=__STATAMIC__.core,{Alert:jo,AuthCard:qo,Avatar:$o,Badge:Qo,Button:Jo,ButtonGroup:Xo,Calendar:Yo,Card:Zo,CardList:er,CardListItem:tr,CardPanel:or,CharacterCounter:rr,Checkbox:nr,CheckboxGroup:ir,CodeEditor:ar,Combobox:m,CommandPaletteItem:sr,ConfirmationModal:lr,Context:dr,ContextFooter:cr,ContextHeader:pr,ContextItem:ur,ContextLabel:mr,ContextMenu:Cr,ContextSeparator:Sr,CreateForm:gr,DatePicker:hr,DateRangePicker:Tr,Description:fr,DocsCallout:vr,DragHandle:br,Dropdown:Pr,DropdownItem:Rr,DropdownLabel:yr,DropdownMenu:wr,DropdownSeparator:xr,DropdownFooter:Mr,DropdownHeader:Ir,Editable:Fr,ErrorMessage:Er,EmptyStateItem:Dr,EmptyStateMenu:Hr,Field:kr,Header:Lr,Heading:Ar,HoverCard:Vr,Icon:_r,Input:Br,InputGroup:Or,InputGroupAppend:zr,InputGroupPrepend:Nr,Label:Gr,Listing:Ur,ListingCustomizeColumns:Kr,ListingFilters:Wr,ListingHeaderCell:jr,ListingPagination:qr,ListingPresets:$r,ListingPresetTrigger:Qr,ListingRowActions:Jr,ListingSearch:Xr,ListingTable:Yr,ListingTableBody:Zr,ListingTableHead:en,ListingToggleAll:tn,LivePreview:on,LivePreviewPopout:rn,MiddleEllipsis:nn,Modal:an,ModalClose:sn,ModalTitle:ln,Pagination:dn,Panel:cn,PanelFooter:pn,PanelHeader:un,Popover:mn,PublishComponents:Cn,PublishContainer:Sn,publishContextKey:gn,injectPublishContext:hn,PublishField:Tn,PublishFields:fn,PublishFieldsProvider:vn,PublishForm:bn,PublishLocalizations:Pn,PublishSections:Rn,PublishTabs:yn,Radio:wn,RadioGroup:xn,Select:Mn,Separator:In,Slider:Fn,Skeleton:En,SplitterGroup:Dn,SplitterPanel:Hn,SplitterResizeHandle:kn,StatusIndicator:Ln,Subheading:An,Switch:Vn,TabContent:_n,Stack:Bn,StackClose:On,StackHeader:zn,StackFooter:Nn,StackContent:Gn,Table:Un,TableCell:Kn,TableColumn:Wn,TableColumns:jn,TableRow:qn,TableRows:$n,TabList:Qn,TabProvider:Jn,Tabs:Xn,TabTrigger:Yn,Text:Zn,Textarea:ei,TimePicker:ti,TimezoneHoverCard:oi,Timezones:ri,ToggleGroup:ni,ToggleItem:ii,Widget:ai,registerIconSet:si,registerIconSetFromStrings:li}=__STATAMIC__.ui,C={__name:"FormFieldsFieldtype",props:e.props,emits:e.emits,setup(r,{expose:n,emit:i}){const a=i,s=r,{expose:l,update:d}=e.use(a,s);return n(l),(t,S)=>(u(),p(o(m),{class:"w-full",clearable:"",searchable:"","model-value":t.value,options:t.meta.options,"option-label":"label","option-value":"value","onUpdate:modelValue":o(d)},null,8,["model-value","options","onUpdate:modelValue"]))}};Statamic.booting(()=>{Statamic.$components.register("form_fields-fieldtype",C)}); diff --git a/resources/dist/build/manifest.json b/resources/dist/build/manifest.json index 06f944f..d111967 100644 --- a/resources/dist/build/manifest.json +++ b/resources/dist/build/manifest.json @@ -1,6 +1,6 @@ { "resources/js/addon.js": { - "file": "assets/addon-Dnt1-tBd.js", + "file": "assets/addon-54LLqdMz.js", "name": "addon", "src": "resources/js/addon.js", "isEntry": true diff --git a/resources/js/addon.js b/resources/js/addon.js index 36ada1c..63b44b1 100644 --- a/resources/js/addon.js +++ b/resources/js/addon.js @@ -1,5 +1,5 @@ -import MailerLiteFormFieldsFieldtype from './components/fieldtypes/MailerLiteFormFieldsFieldtype.vue'; +import FormFieldsFieldtype from './components/fieldtypes/FormFieldsFieldtype.vue'; Statamic.booting(() => { - Statamic.$components.register('mailer_lite_form_fields-fieldtype', MailerLiteFormFieldsFieldtype); + Statamic.$components.register('form_fields-fieldtype', FormFieldsFieldtype); }); diff --git a/resources/js/components/fieldtypes/MailerLiteFormFieldsFieldtype.vue b/resources/js/components/fieldtypes/FormFieldsFieldtype.vue similarity index 100% rename from resources/js/components/fieldtypes/MailerLiteFormFieldsFieldtype.vue rename to resources/js/components/fieldtypes/FormFieldsFieldtype.vue diff --git a/src/Fieldtypes/MailerLiteFormFields.php b/src/Fieldtypes/FormFields.php similarity index 96% rename from src/Fieldtypes/MailerLiteFormFields.php rename to src/Fieldtypes/FormFields.php index b616ee7..02d0487 100644 --- a/src/Fieldtypes/MailerLiteFormFields.php +++ b/src/Fieldtypes/FormFields.php @@ -7,7 +7,7 @@ use Statamic\Fields\Field; use Statamic\Fields\Fieldtype; -class MailerLiteFormFields extends Fieldtype +class FormFields extends Fieldtype { protected $selectable = false; diff --git a/src/StatamicMailerLiteServiceProvider.php b/src/StatamicMailerLiteServiceProvider.php index 02718dd..b464be7 100644 --- a/src/StatamicMailerLiteServiceProvider.php +++ b/src/StatamicMailerLiteServiceProvider.php @@ -64,7 +64,7 @@ public static function configFields(): array [ 'handle' => 'form_field', 'field' => [ - 'type' => 'mailer_lite_form_fields', + 'type' => 'form_fields', 'display' => __('Form field'), ], ], diff --git a/tests/Feature/MailerLiteFormFieldsFieldtypeTest.php b/tests/Feature/FormFieldsFieldtypeTest.php similarity index 81% rename from tests/Feature/MailerLiteFormFieldsFieldtypeTest.php rename to tests/Feature/FormFieldsFieldtypeTest.php index 47df0c6..49e9518 100644 --- a/tests/Feature/MailerLiteFormFieldsFieldtypeTest.php +++ b/tests/Feature/FormFieldsFieldtypeTest.php @@ -1,6 +1,6 @@ setRouteResolver(fn (): Route => $route); - $options = (new MailerLiteFormFields)->preload()['options']; + $options = (new FormFields)->preload()['options']; expect(collect($options)->pluck('value')->all())->toBe([ 'email', @@ -32,7 +32,7 @@ }); it('preloads an empty option list when the route has no form', function () { - expect((new MailerLiteFormFields)->preload()['options'])->toBe([]); + expect((new FormFields)->preload()['options'])->toBe([]); }); it('preloads an empty option list when a form handle cannot be resolved', function () { @@ -41,5 +41,5 @@ request()->setRouteResolver(fn (): Route => $route); - expect((new MailerLiteFormFields)->preload()['options'])->toBe([]); + expect((new FormFields)->preload()['options'])->toBe([]); }); diff --git a/tests/Feature/MailerLiteConfigFieldsTest.php b/tests/Feature/MailerLiteConfigFieldsTest.php index 854cf35..6e8d880 100644 --- a/tests/Feature/MailerLiteConfigFieldsTest.php +++ b/tests/Feature/MailerLiteConfigFieldsTest.php @@ -29,5 +29,5 @@ $formField = collect($fields['mailerlite_field_mapping']['fields']) ->firstWhere('handle', 'form_field')['field']; - expect($formField['type'])->toBe('mailer_lite_form_fields'); + expect($formField['type'])->toBe('form_fields'); }); From dfb86100ec2965b8e9efeeaa40299dffb465a942 Mon Sep 17 00:00:00 2001 From: Jan Henk Hazelaar Date: Mon, 13 Jul 2026 20:03:29 +0200 Subject: [PATCH 3/3] Hide group and field mapping until sync is enabled The Group and Field mapping fields are meaningless while MailerLite sync is off, so they now only appear once the toggle is enabled, keeping the form configure page uncluttered. Changelog: changed --- src/StatamicMailerLiteServiceProvider.php | 6 ++++++ tests/Feature/MailerLiteConfigFieldsTest.php | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/src/StatamicMailerLiteServiceProvider.php b/src/StatamicMailerLiteServiceProvider.php index b464be7..66d475f 100644 --- a/src/StatamicMailerLiteServiceProvider.php +++ b/src/StatamicMailerLiteServiceProvider.php @@ -53,6 +53,9 @@ public static function configFields(): array 'instructions' => __('Subscribers will be added to this MailerLite group.'), 'mode' => 'select', 'max_items' => 1, + 'show_when' => [ + 'mailerlite_enabled' => true, + ], ], 'mailerlite_field_mapping' => [ 'type' => 'grid', @@ -60,6 +63,9 @@ public static function configFields(): array 'display' => __('Field mapping'), 'instructions' => __('Map each form field to a MailerLite subscriber field.'), 'add_row' => __('Add mapping'), + 'show_when' => [ + 'mailerlite_enabled' => true, + ], 'fields' => [ [ 'handle' => 'form_field', diff --git a/tests/Feature/MailerLiteConfigFieldsTest.php b/tests/Feature/MailerLiteConfigFieldsTest.php index 6e8d880..995cca8 100644 --- a/tests/Feature/MailerLiteConfigFieldsTest.php +++ b/tests/Feature/MailerLiteConfigFieldsTest.php @@ -31,3 +31,11 @@ expect($formField['type'])->toBe('form_fields'); }); + +it('only shows the group and field mapping when sync is enabled', function () { + $fields = StatamicMailerLiteServiceProvider::configFields(); + + expect($fields['mailerlite_enabled'])->not->toHaveKey('show_when'); + expect($fields['mailerlite_group']['show_when'])->toBe(['mailerlite_enabled' => true]); + expect($fields['mailerlite_field_mapping']['show_when'])->toBe(['mailerlite_enabled' => true]); +});