Newsletter 365tipů můžete číst zdarma. Placené předplatné je dobrovolná podpora, která pomáhá webu pokračovat.
Podpořit 365tipů

TIP#3318: Co dělat, když WordPress po smazání pluginu nebo šablony hlásí chyby .l10n.php?

Stalo se mi to během krátké doby na dvou různých webech – po odstranění pluginu či nepotřebné šablony začal WordPress v administraci zobrazovat PHP warningy týkající se chybějících .l10n.php souborů. Na živém webu přitom žádné chyby nebyly. Řešení je naštěstí velmi jednoduché, jen ho WordPress schovává úplně dole na stránce s aktualizacemi.

POZNÁMKA: Jako u jiných aktuálních článků i toto je dílo AI, které opět zaslouží vysvětlení. S Claude jsem řešil problém, nepřišla na to, přišel jsem na to já (Claude je v poslední době 1000% sebevědomí, ale zásadně se neobtěžuje něco hledat a ověřovat dokud k tomu není donucena). Od ní pak šel souhrn do „skill“ 365tipů v ChatGPT pro napsání tipu. Nejdřív to otočila okolo „mazání přes FTP“ (které to taky může způsobit, ale tady to důvod nebyl), pak zapomněla přidat odkazy na nalezené věci, nakonec jsem ji musel nechat napsat titulek a perex co na sebe správně navazují?

A pak sice doplnila chybějící odkazy (po upozornění), ale ne do textu odstavců, ale zcela odděleně kamsi na konec (to jsem už opravil ručně). Takže jako obvykle, člověk editorem pro AI. Ale pořád je to rychlejší než to celé napsat písmenko písmenku. Jo a aspoň „omlouvat se“to umí.

Typický warning vypadá nějak takto:

Warning: include(.../wp-content/languages/themes/twentytwentyfour-cs_CZ.l10n.php):
Failed to open stream: No such file or directory

Případně místo themes uvidíte plugins a samozřejmě název konkrétního odstraněného pluginu.

Důležité je, že v případech, na které jsem narazil, se warningy objevovaly jen v administraci WordPressu a ani tam ne všude. Třeba při přechodu do Vzhled → Šablony. Veřejná část webu byla bez warningů a normálně fungovala.

Nejjednodušší řešení? Aktualizovat překlady

Jděte do Nástěnka → Aktualizace a odrolujte úplně dolů.

Ano, úplně dolů.

Najdete tam část Překlady a pokud WordPress nabízí jejich aktualizaci, také tlačítko Aktualizovat překlady.

Použijte ho.

V obou případech, kdy jsem tento problém řešil, warningy po aktualizaci překladů zmizely.

Je to mimochodem jedna z těch funkcí WordPressu, o kterých spousta lidí nejspíš vůbec neví. Není divu, tlačítko je schované až na úplném konci stránky Aktualizace.

Co jsou .l10n.php a proč s nimi může být problém?

Od WordPressu 6.5 se změnil způsob práce s překlady. Vedle tradičních .po a .mo souborů se používají také PHP soubory s příponou .l10n.php. Pokud jsou k dispozici, WordPress je načítá přednostně před .mo, protože je tento způsob rychlejší. Podrobnosti najdete v dokumentaci změn ve WordPressu 6.5. I18N Improvements in WordPress 6.5 – Performant Translations

WordPress si navíc kvůli výkonu ukládá do cache seznam překladových souborů, které v příslušných adresářích našel. Aktuální WP_Textdomain_Registry hledá .mo i .l10n.php soubory, jejich seznam ukládá do object cache pod skupinou translation_files a cache má platnost jednu hodinu. WP_Textdomain_Registry v dokumentaci WordPressu

A právě tady je nejspíš zakopaný pes.

Odstraníte plugin nebo šablonu, s nimi zmizí jejich překladové soubory, ale WordPress může mít ještě v cache jejich dříve nalezené cesty. Některá část administrace pak se starým seznamem pracuje a pokusí se načíst něco, co už na disku není.

Výsledkem je například:

Failed to open stream: No such file or directory

To je mimochodem důležitý detail: problém není v tom, že by po odstraněném pluginu či šabloně nutně zůstal nějaký „osiřelý“ .l10n.php soubor. Warning naopak říká, že se WordPress snaží načíst soubor, který na uvedené cestě není.

Není to jen moje specialita

Velmi podobný problém už je popsán přímo ve WordPress Tracu.

V ticketu #64236 – Warning messages when deleting any plugin in WP 6.9 RC1 se po zcela normálním odstranění pluginu z administrace objevily prakticky stejné warningy:

include(.../wp-content/languages/plugins/...l10n.php):
Failed to open stream: No such file or directory

Plugin přitom byl úspěšně odstraněn. Autor problém zkoušel na dvou různých hostingových službách a objevil se pouze na jedné. Proto se ho nepodařilo spolehlivě reprodukovat a ticket byl uzavřen jako invalid – nikoliv jako opravený bug.

To je docela podstatné i proto, že pro vznik problému nemusíte nic mazat přes FTP, SSH ani přes správce souborů hostingu. Já jsem na něj narazil po běžném odstranění pluginu nebo nepotřebné šablony a stejnou zkušenost popisuje zmíněný ticket.

Jestli jde o konkrétní současný bug WordPressu, bych zatím netvrdil. Problém evidentně není univerzálně reprodukovatelný a může záviset i na konkrétní konfiguraci webu, hostingu nebo object cache.

WordPress už problémy s cache překladů řešil

Není to navíc poprvé, kdy cachování seznamu překladových souborů způsobilo potíže.

WordPress Trac #60764 – Translation file cache never expires, causes issues for atomic filesystems řešil situaci, kdy tato cache původně neměla expiraci. Pokud se obsah adresáře s překlady změnil jiným způsobem, než WordPress očekával, mohl dál pracovat se zastaralým seznamem souborů.

Součástí změn bylo zavedení expirace; v současném WordPressu se seznam překladových souborů cachuje na jednu hodinu.

Ticket #60764 samozřejmě není důkaz, že přesně stejná chyba způsobuje warningy po odstranění pluginu či šablony. Ukazuje ale, že zastaralý seznam překladových souborů je reálný problém, se kterým už WordPress musel pracovat.

Proč pomůže právě Aktualizovat překlady?

Protože při aktualizaci jazykových balíčků WordPress cache překladových souborů invaliduje.

WP_Textdomain_Registry je napojený na dokončení upgradu a při aktualizaci překladů smaže příslušný záznam z cache translation_files pro pluginy, šablony nebo samotný WordPress. Při příštím použití se tak seznam souborů vytvoří znovu podle toho, co je skutečně na disku. WP_Textdomain_Registry::invalidate_mo_files_cache()

Language Pack Upgrader navíc po aktualizaci překladů standardně volá wp_clean_update_cache(), tedy čistí i cache informací o aktualizacích WordPressu, pluginů a šablon. Language_Pack_Upgrader::bulk_upgrade()

Proto je tlačítko Aktualizovat překlady tak dobré první řešení. Neřeší jen jeden náhodně vybraný záznam v databázi, ale nechá samotný WordPress udělat úklid věcí souvisejících s překlady a aktualizacemi.

A co smazání _site_transient_update_themes?

Při hledání řešení můžete narazit i na doporučení ručně smazat:

_site_transient_update_themes

například SQL příkazem:

DELETE FROM wp_options
WHERE option_name = '_site_transient_update_themes';

Tohle bych jako řešení tohoto problému nedoporučoval.

update_themes skutečně obsahuje cachované informace související s aktualizacemi šablon a WordPress ho například po odstranění šablony sám maže. V aktuální implementaci delete_theme() je vidět jak odstranění jazykových souborů .po, .mo a .l10n.php, tak následné delete_site_transient( 'update_themes' ). delete_theme() v dokumentaci WordPressu

Jenže _site_transient_update_themes není totéž jako cache seznamu překladových souborů translation_files, která je pro zde popsaný problém podstatná.

Smazání tohoto transientu tedy může v některých situacích pomoci s informacemi o aktualizacích šablon, ale není správné tvrdit, že jde o ekvivalent tlačítka Aktualizovat překlady.

A už vůbec není důvod kvůli několika warningům začínat ručním zásahem do databáze, když existuje jednoduchá cesta přímo v administraci.

A co když šablonu nebo plugin smažete přes FTP?

To je trochu jiný případ a může přidat další problémy.

Pokud například odstraníte šablonu normálně ve WordPressu, delete_theme() nemaže pouze její adresář. WordPress se pokusí odstranit také její překlady .po, .mo, .l10n.php a související JSON soubory, vyčistí cache šablony a vynutí obnovení informací o aktualizacích.

Když pouze smažete adresář přes FTP, nic z tohoto úklidu se neprovede.

Není to ale příčina problému popisovaného v tomto tipu – jak už bylo řečeno, warningy se mohou objevit i po naprosto standardním odstranění pluginu či šablony z administrace.

Pokud WordPress funguje, je každopádně lepší pluginy a šablony mazat přímo v něm. Ruční odstranění adresáře si nechte spíš jako řešení situací, kdy se kvůli rozbitému pluginu či šabloně do administrace vůbec nedostanete.

Takže ještě jednou: co dělat

Pokud po odstranění pluginu nebo šablony začnete v administraci WordPressu vídat PHP warningy obsahující něco jako:

wp-content/languages/plugins/
wp-content/languages/themes/
.l10n.php
Failed to open stream: No such file or directory

a živý web přitom normálně funguje, zkuste jako první:

Nástěnka → Aktualizace → odrolovat úplně dolů → Překlady → Aktualizovat překlady.

V mém případě to problém odstranilo na dvou webech.

A pokud nepomůže? Pak už samozřejmě bude čas podívat se do logů, na object cache, konkrétní plugin či šablonu a další možné příčiny. Ale nezačínal bych SQL příkazy a ručním mazáním souborů.

Související tipy

Hodit se bude TIP#2223: Ponechat na WordPress webu pouze aktivní šablonu nebo i jednu z výchozích? Staré a nepoužívané šablony nemá smysl na webu hromadit, jednu aktuální výchozí je ale užitečné ponechat jako záložní.

Viz také TIP#2495: Mohu z mého WordPressu odstranit plugin tak, že smažu složku s pluginem? – právě k rozdílu mezi normálním odstraněním pluginu a prostým smazáním jeho adresáře.

A samozřejmě TIP#2074: Aktualizace WordPressu, jak na to? Mám nechat automaticky aktualizovat? Jak s pluginy a šablonou?, kde je mimo jiné řeč o Nástěnka → Aktualizace i aktualizacích překladů.

Při úklidu novější instalace se může hodit také TIP#3228: Co byste po instalaci WordPressu měli smazat či změnit? Další soubory.