Fyra serviceluckor i rad i en stationshall, en kund vid varje lucka. Vänstra luckan har en synlig handläggare som expedierar kunden, medan de tre övriga luckorna är obemannade bakom glaset trots att kunder väntar vid dem — en metafor för hur max_input_vars tyst slutar ta emot formulärfält utan varning.
Guider

Därför försvinner dina WordPress-menyer och produktvarianter när du sparar

Du bygger en meny med sextio länkar i WordPress, eller lägger till en produkt i WooCommerce med tjugo färger och femton storlekar i variantmatrisen. Du klickar spara. Sidan laddar om, allt ser ut som det ska på ytan. Sen upptäcker du att hälften av menyposterna är borta, eller att produktvarianterna du precis skapade helt enkelt inte finns längre. Inget felmeddelande. Ingen röd ruta. Bara tyst frånvaro.

Vi har sett exakt det här hos flera kunder, och första reaktionen är nästan alltid densamma. Man tror att man har klickat fel, eller glömt spara, så man gör om det. Fyller i menyn igen, sparar igen, och tappar ännu fler poster på vägen. Det är en fullt logisk reaktion på ett problem som inte alls handlar om användarfel. Det handlar om en gräns i PHP-konfigurationen som heter max_input_vars, och den är den enda av WordPress fyra vanliga PHP-gränser som inte säger ifrån när du slår i den.

Den tysta trunkeringen

max_input_vars är gränsen för hur många formulärfält servern tar emot i en enda sparning. Standardvärdet i PHP är 1000, och det gäller $_GET, $_POST och $_COOKIE var för sig. Enligt php.nets egen dokumentation är effekten när gränsen nås följande, ordagrant citerat: "If there are more input variables than specified by this directive, an E_WARNING is issued, and further input variables are truncated from the request."

Lägg märke till ordvalet. Ett E_WARNING utfärdas, ja, men det landar i serverns fellogg, inte i webbläsaren. Ingen dialogruta, ingen röd text ovanför formuläret, ingenting som talar om för dig att data faktiskt kapades bort mitt i sparningen. Om du misstänker att du har råkat ut för det här är alltså det första du bör göra att öppna webbhotellets fellogg och leta efter en rad med just E_WARNING och max_input_vars i texten. Den raden finns nästan alltid där, den bara visas aldrig för dig som redaktör.

Varför hela menyposter försvinner, inte bara de nya

Det som gör den här gränsen extra otäck i just menyer är hur WordPress mekanik för att spara en meny fungerar. När du sparar går WordPress igenom hela $_POST-arrayen och jämför den med de menyposter som redan finns i databasen. Poster som inte längre finns med i den inskickade arrayen tolkas inte som "oförändrade". De tolkas som borttagna, och raderas.

Om PHP redan har kapat bort delar av formuläret innan WordPress ens får se det, vet WordPress ingenting om att de kapade posterna någonsin existerade i sparningen. Resultatet blir inte att "de nya menyposterna inte sparas". Resultatet blir att befintliga menyposter, sådana som legat där i månader, försvinner ur menyn. Varje menypost skickar med sig ungefär elva till tolv separata fält (ID, titel, url, ordning, förälder, klasser och så vidare), så med standardtaket på 1000 räcker det ungefär till 80 till 90 menyposter innan gränsen börjar äta. En stor sajt med flera nivåer i huvudmenyn, en megameny eller flera språkversioner når dit fortare än man tror.

Fyra gränser, tre högljudda och en tyst

WooCommerce pekar själva ut fyra PHP-inställningar som avgör om tunga formulär sparas korrekt. Tre av dem är obehagliga när du slår i taket, men de är åtminstone ärliga om det.

  • max_execution_time ger dig en synlig timeout eller en vit sida (ofta ett 500-fel) om skriptet tar för lång tid.
  • upload_max_filesize ger ett tydligt uppladdningsfel i mediabiblioteket när en fil är för stor.
  • post_max_size ger också ett synligt fel, eller i värsta fall ett tomt $_POST, men det märks direkt eftersom hela formuläret plötsligt är blankt.
  • max_input_vars ger ingenting alls. Data trunkeras, sparningen "lyckas", och du får reda på det först när du själv upptäcker att något saknas.

Det är den fjärde gränsen som är farlig, av precis det skälet att den inte är farlig på det sätt du är van vid att gränser är farliga. Du lär dig snabbt att respektera en gräns som kraschar sidan. Du lär dig aldrig att respektera en gräns som bara stjäl data i tystnad.

Var gränsen slår hårdast

Menyer är ett tydligt exempel, men knappast det vanligaste. Variabla produkter i WooCommerce är där vi ser problemet oftast, av det enkla skälet att antalet formulärfält växer multiplikativt. Tre attribut med fem värden vardera ger en variantmatris som snabbt genererar hundratals enskilda fält (pris, lager, SKU, vikt per variant) för en enda produkt. Lägg till en sidbyggare som Elementor eller WPBakery, där varje sektion, kolumn och widget adderar egna dolda fält, eller ett anpassat fältpaket som ACF eller Meta Box på en innehållsrik sida, så är du plötsligt uppe i tusentals fält för en enskild sparning. Stora kontaktformulär med många valfria fält kan också nå dit, även om det tar fler fält att komma dit än man tror.

Gemensamt för alla dessa fall är att ingen av dem känns som "en stor sajt" när man bygger den. Det är en produkt, en meny, en sida, byggd steg för steg under en eftermiddag. Ingen sätter sig ner och räknar formulärfält i förväg.

Så kontrollerar du var gränsen ligger

Innan du ändrar något, ta reda på var du faktiskt står. WooCommerce har en inbyggd sida för det, under WooCommerce → Status, som visar det aktiva värdet på max_input_vars direkt i serverinformationen. WordPress egen Verktyg → Webbplatshälsa ger en liknande, om än mindre detaljerad, bild av PHP-miljön. Vill du ha hela sanningen kan du alltid lägga en phpinfo()-fil på servern tillfälligt och leta upp raden för direktivet där, men kom ihåg att ta bort filen igen efteråt.

Höj gränsen rätt, och verifiera att den tog

WooCommerce egen dokumentation är rak på sak om vad som händer om du inte agerar. Ordagrant, från deras felsökningssida, "your data may be silently truncated when you save". De rekommenderar att höja värdet till 3000, vilket ger god marginal utan att öppna dörren på vid gavel för de överbelastningsattacker som gränsen från början är till för att dämpa (PHP:s egen motivering handlar om att begränsa hash-kollisionsbaserad DoS, så höj med måtta snarare än att panik-inflatera till ett orimligt tal).

Här blir det knepigt, för det populära tipset att bara lägga en rad i .htaccess fungerar inte överallt, och du får aldrig veta om det gällde din server förrän du kontrollerar.

php_value max_input_vars 3000

Den här raden biter bara om servern kör PHP som Apache-modul (mod_php) eller via LiteSpeed/lsphp, där servern faktiskt läser direktiv ur .htaccess. Flera svenska cPanel-webbhotell, till exempel Oderland, kör LiteSpeed och läser den här filen precis som väntat. Kör servern i stället PHP-FPM, suPHP eller CGI, ignoreras raden helt, eller ger i värsta fall ett eget 500-fel. Då måste värdet i stället in i en .user.ini-fil i samma mapp, eftersom max_input_vars är ett så kallat PHP_INI_PERDIR-direktiv som PHP känner igen där oavsett handler.

max_input_vars = 3000

Det finns också ett tredje sätt som du kan stöta på i olika WordPress-forum, att lägga ini_set('max_input_vars', 3000) i temats functions.php. Det biter aldrig, oavsett vilken handler servern kör, just för att direktivet är PHP_INI_PERDIR och därmed inte går att ändra vid körning från PHP-kod. Det går bara att sätta i konfigurationsfiler eller i webbhotellets PHP-panel.

Den mest pålitliga vägen är därför webbhotellets egen PHP-inställningspanel. I cPanel heter den vanligen "Select PHP version" följt av en Options-flik (på vissa installationer kallad MultiPHP INI Editor). I DirectAdmin hittar du motsvarande under den egna PHP-konfigurationen, som i grunden också skriver till en .user.ini. Oavsett väg gäller samma sista steg. Gå tillbaka till WooCommerce → Status eller din phpinfo()-utskrift och bekräfta att det nya värdet faktiskt visas där. Annars vet du inte om ändringen tog, du bara hoppas det.

Det är värt att förstå att standardvärdet på 1000 inte är ett tecken på ett dåligt webbhotell. Det är PHP:s egen standardinställning, satt av samma säkerhetsskäl överallt. Frågan är aldrig om webbhotellets gräns är för snål i sig, utan om du har kontrollerat den, höjt den vid behov och verifierat att höjningen faktiskt slog igenom på din specifika serverkonfiguration.

Om du har läst vår genomgång av varför WooCommerce kraschar med tydliga felmeddelanden på billigt webbhotell känner du igen mönstret från motsatt håll, högljudda krascher är obehagliga men ärliga. Den tysta varianten är den som faktiskt kostar dig data. Letar du efter ett webbhotell som redan är konfigurerat med rimliga PHP-gränser för tunga WordPress-sajter kan vår genomgång av webbhotell optimerade för WordPress vara en bra utgångspunkt.

Nästa gång en meny eller en produktvariant försvinner utan förklaring vet du i alla fall var du ska börja leta, inte i vad du gjorde fel, utan i en enda tyst rad längst ner i felloggen.