Skip to content

Allt om WordPress, webbutveckling — och mer därtill

🚀 Hur du kopplar in dig i Contact Form 7 före formulärinskick

🚀 Hur du kopplar in dig i Contact Form 7 före formulärinskick

Contact Form 7 är installerat på miljontals WordPress-sajter. Det är enkelt, pålitligt och gratis. Men så fort standardbeteendet inte räcker till och du behöver validera ett fält, sätta en dynamisk mottagare eller avbryta ett mejl baserat på ett villkor, hamnar du i "hur gör man ens detta"-träsket.

Dokumentationen för CF7 beskriver hooks kortfattat. Forum och Stack Overflow är fulla av kodsnuttar för gamla pluginversioner, och fem år gammal kod slutar fungera tyst på moderna CF7. Låt oss reda ut vilka hooks som är aktuella idag och hur du kopplar in dig i dem utan överraskningar.

💡 Snabb översikt:

  • den huvudsakliga hooken är wpcf7_before_send_mail, ingångspunkten för all logik före sändning.
  • du kan hoppa över mejlet med filtret wpcf7_skip_mail eller en enda rad skip_mail: on i formulärinställningarna.
  • för att hämta inskickad data använder du objektet $submission och metoden get_posted_data().
  • för att ändra mottagaren dynamiskt använder du set_properties() på formulärobjektet.
  • för fältvalidering använder du wpcf7_validate med ett filter per fälttyp.

Varför du behöver hooks före sändning

Standardscenariot för CF7 ser ut så här: en användare fyller i fält, klickar på "Skicka", och pluginet skickar ett mejl till en fast adress. Det är allt. Att lägga till logik i denna process utan hooks är omöjligt.

Hooken wpcf7_before_send_mail och relaterade filter låter dig ingripa i kedjan precis i det ögonblick då data har validerats men mejlet ännu inte har skickats. Du kan:

  • kontrollera ett anpassat villkor och avbryta inskickningen;
  • spara formulärdata till en databas eller externt API;
  • ändra mejlmottagaren i farten;
  • modifiera mejlinnehållet;
  • utlösa en integration med ett CRM eller en e-posttjänst.

Alla exempel nedan fungerar med Contact Form 7 version 5.2 och senare. Om ditt plugin är äldre, uppdatera först: gamla hook-signaturer är inkompatibla.

Wpcf7_before_send_mail, ingångspunkten

Från och med version 5.2 ändrades hook-signaturen. Tidigare skickades bara formulärobjektet med; nu finns det tre argument:

1add_filter( 'wpcf7_before_send_mail', 'cf7_before_send_handler', 10, 3 );
2
3function cf7_before_send_handler( $contact_form, $abort, $submission ) {
4 // $contact_form — WPCF7_ContactForm object
5 // $abort — abort flag (true/false)
6 // $submission — WPCF7_Submission object with data
7
8 // your logic here
9
10 return $contact_form;
11}

Fil för placering: functions.php i ditt aktiva tema eller tillägget Code Snippets. Prioriteten 10 fungerar för de flesta uppgifter; höj den till 1 om din callback behöver köras före andra, eller sänk den till 99 om den ska köras efter.

Observera att denna hook är ett filter, inte en action. Du måste returnera objektet $contact_form (eller WPCF7_ContactForm), annars bryts kedjan på fel sätt.

Hoppa över mejlsändning

Det vanligaste användningsfallet: skicka inte en notifiering om ett fält är ifyllt på ett specifikt sätt. Det finns två tillvägagångssätt.

Använda filtret wpcf7_skip_mail

Kort och rent. Filtret accepterar ett booleskt värde och formulärobjektet:

1add_filter( 'wpcf7_skip_mail', 'maybe_skip_mail', 10, 2 );
2
3function maybe_skip_mail( $skip_mail, $contact_form ) {
4 $submission = WPCF7_Submission::get_instance();
5
6 if ( $submission ) {
7 $data = $submission->get_posted_data();
8
9 // do not send email if field your-reason equals 'test'
10 if ( 'test' === ( $data['your-reason'] ?? '' ) ) {
11 $skip_mail = true;
12 }
13 }
14
15 return $skip_mail;
16}

Metoden WPCF7_Submission::get_instance() ger tillgång till inskickningsdata inom detta filter. Utan den är get_posted_data() otillgänglig eftersom $submission inte skickas direkt till wpcf7_skip_mail.

Använda ytterligare inställningar

Om logiken är så enkel som den kan bli (hoppa alltid över mejlet för ett specifikt formulär), gå till adminpanelen. På formulärets flik "Ytterligare inställningar" lägger du till en rad:

1skip_mail: on

Ingen kod behövs. Pluginet stoppar mejlsändningen direkt efter validering, och användaren ser ett framgångsmeddelande. Perfekt för demoformulär och testmiljöer.

Ett alternativ med samma effekt: demo_mode: on. Skillnaden är att demo_mode fullständigt simulerar framgång utan att röra mejlundersystemet, medan skip_mail bara hoppar över sändningssteget och bevarar allt annat beteende.

Hämta inskickad data

Objektet $submission (det tredje argumentet till wpcf7_before_send_mail) ger full tillgång till vad användaren skickade in:

1add_filter( 'wpcf7_before_send_mail', 'cf7_read_form_data', 10, 3 );
2
3function cf7_read_form_data( $contact_form, $abort, $submission ) {
4 // all fields at once
5 $posted = $submission->get_posted_data();
6
7 // specific field (key — name attribute of the tag in the form)
8 $user_name = $submission->get_posted_data( 'your-name' );
9 $user_email = $submission->get_posted_data( 'your-email' );
10
11 // ID of the post from which the form was sent
12 $post_id = $submission->get_meta( 'container_post_id' );
13
14 // form ID
15 $form_id = $contact_form->id();
16
17 // save to log or external service
18 if ( $user_email ) {
19 // for example, add subscriber to mailing list
20 }
21
22 return $contact_form;
23}

Fältnycklar ('your-name', 'your-email') är värdena för attributet name i formulärets shortcodes. Standardtaggar som [text* your-name], [email* your-email] producerar nycklar utan prefix; kopiera bara det som kommer efter mellanslaget.

Viktigt: get_posted_data() returnerar data före bearbetning av mejlmallar. Specialtecken, radbrytningar, allt precis som användaren skrev in det. Sanera innan du sparar till databasen med sanitize_text_field() eller liknande funktioner.

Dynamiskt mottagarbyte

Anta att mejlet ska gå till olika handläggare beroende på vilket ämne som valts i formuläret. Vi ändrar egenskapen recipient i farten:

1add_filter( 'wpcf7_before_send_mail', 'cf7_dynamic_recipient', 10, 3 );
2
3function cf7_dynamic_recipient( $contact_form, $abort, $submission ) {
4 $data = $submission->get_posted_data();
5 $department = $data['your-department'] ?? '';
6
7 $recipients = [
8 'sales' => '[email protected]',
9 'support' => '[email protected]',
10 'billing' => '[email protected]',
11 ];
12
13 if ( isset( $recipients[ $department ] ) ) {
14 $props = $contact_form->get_properties();
15 $props['mail']['recipient'] = $recipients[ $department ];
16 $contact_form->set_properties( $props );
17 }
18
19 return $contact_form;
20}

Metoderna get_properties() och set_properties() arbetar med formulärets inställningsarray, inklusive sektionen mail. Du kan ändra inte bara mottagaren utan även ämnet (subject), innehållet (body), ytterligare headers (additional_headers) och avsändaren (sender).

Placera koden på samma ställe: ditt temas functions.php eller via Code Snippets. Testa på staging innan du driftsätter i produktion: ett stavfel i arraynyckeln mail ignoreras tyst, och mejlet går till standardadressen.

Fältvalidering före sändning

CF7 tillhandahåller filtret wpcf7_validate, som körs före wpcf7_before_send_mail. Det tar emot ett WPCF7_Validation-objekt och låter dig lägga till ett fel; formuläret skickas inte förrän användaren åtgärdar det:

1add_filter( 'wpcf7_validate_text*', 'cf7_custom_text_validation', 10, 2 );
2add_filter( 'wpcf7_validate_email*', 'cf7_custom_email_validation', 10, 2 );
3
4function cf7_custom_text_validation( $result, $tag ) {
5 $field_name = $tag->name;
6
7 if ( 'your-message' === $field_name ) {
8 $value = $_POST[ $field_name ] ?? '';
9
10 if ( mb_strlen( $value ) < 20 ) {
11 $result->invalidate( $tag, 'Message must be at least 20 characters long.' );
12 }
13 }
14
15 return $result;
16}
17
18function cf7_custom_email_validation( $result, $tag ) {
19 $value = $_POST[ $tag->name ] ?? '';
20
21 if ( $value && ! str_contains( $value, '@' ) ) {
22 $result->invalidate( $tag, 'Enter a valid email.' );
23 }
24
25 return $result;
26}

Filtret namnges enligt mönstret wpcf7_validate_<field type>: text* för obligatoriska textfält, email* för e-post, textarea* för textytor. Utan asterisken gäller det valfria fält. $tag är ett objekt med formulärfältsparametrar, inklusive name.

Fel läggs till med metoden invalidate($tag, 'error text'). Texten är godtycklig och visas under formulärfältet. Vid AJAX-inskickning (standard i CF7) visas meddelandet utan att sidan laddas om.

⁉️🤔 Vanliga frågor

Vad är skillnaden mellan wpcf7_before_send_mail och wpcf7_mail_sent?

wpcf7_before_send_mail körs före mejlet skickas; du kan avbryta mejlet, ändra mottagaren eller modifiera data i det. wpcf7_mail_sent är en action som körs efter lyckad sändning. Använd den för loggning, triggning av webhooks eller databasskrivningar när mejlet garanterat har skickats. Om du behöver avbryta processen fungerar bara before_send_mail.

Kan jag koppla in mig utan att redigera functions.php?

Ja, via tillägget Code Snippets (gratis, i WordPress arkiv). Det ger ett gränssnitt för att lägga till PHP-snuttar utan att röra temat. Snuttar kan aktiveras och inaktiveras individuellt, vilket är praktiskt för felsökning. Ett alternativ är WPCode (tidigare Insert Headers and Footers), också gratis och med omfattningskontroll; du kan binda en snutt till ett specifikt formulär via villkorslogik.

Hur kontrollerar jag att hooken faktiskt körs?

Det enklaste sättet: error_log( 'HOOK FIRED' ) inuti callback-funktionen och kontrollera wp-content/debug.log med WP_DEBUG aktiverat. För snabb felsökning utan loggar, ersätt tillfälligt return $contact_form med wp_die('Hook works'). Gör inte detta på en produktionssajt; endast på lokal miljö eller staging.

Vad ska jag göra om min kod slutar fungera efter en CF7-uppdatering?

Kontrollera först hook-signaturen. I version 5.2 ökade antalet argument för wpcf7_before_send_mail från 1 till 3. Om din callback deklareras utan parametern $submission, lägg till den. För det andra, verifiera att din funktion returnerar objektet $contact_form. För det tredje, kontrollera PHP-felloggen; CF7 ignorerar tyst fatala fel inuti hooks, formuläret skickas som vanligt, och du ser inte problemet.

Finns det ett sätt att prenumerera på flera formulär med en hook?

Ja, wpcf7_before_send_mail körs för alla formulär. Inuti callbacken filtrerar du efter ID: $contact_form->id() returnerar ett nummer som matchar formulärets shortcode-ID (till exempel [contact-form-7 id="42"]). Jämför det med de önskade ID:na och kör olika logik via if eller switch.

Vad som ska ligga i temats functions vs. brytas ut till ett plugin

CF7-hooks fungerar tekniskt sett var som helst ifrån: functions.php, Code Snippets, MU-plugin. Men det finns en praktisk uppdelning som sparar huvudvärk när du byter tema eller uppdaterar.

Kod som är knuten till affärslogik (mottagarbyte, CRM-integration, databassparningar) bör ligga i ett separat plugin eller Code Snippets. Anledningen är enkel: temabyten ska inte bryta klientens mejlrutning. Fältvalidering, som ofta är knuten till temats layout och klasser, kan ligga kvar i functions.php; den förlorar ändå sin mening när temat byts.

Snuttar längre än 30 rader bör formateras som ett MU-plugin (wp-content/mu-plugins/cf7-custom.php). MU-plugins kan inte inaktiveras från adminpanelen, körs före vanliga plugins och kräver ingen aktivering; lägg bara in filen så fungerar koden.

För helt isolerade fall (ett formulär, en sajt), använd functions.php plus ett barntema. Färre filer, mindre förvirring.

Samma principer gäller för alla andra formulärplugins, oavsett om det är WPForms, Gravity Forms eller Fluent Forms. Var och en har sina egna hooks, men det arkitektoniska angreppssättet "affärslogik separat, presentationslogik med temat" är universellt.

Videon ger en steg-för-steg-genomgång av anpassad CF7-fältvalidering med ett live-exempel i WordPress adminpanel. Tillvägagångssättet är kompatibelt med filtret wpcf7_validate som beskrivs ovan, så se den som ett visuellt komplement till koden från valideringsavsnittet.