Ažuriranje WordPress-a na verziju 7.1 može izazvati ozbiljne probleme sa WP Rocket. Otkrij efikasne načine kako da se nosiš sa ovom greškom i ponovo aktiviraš svoj sajt.
Šta ćeš naučiti
- Razlozi za grešku "There has been a critical error"
- Kako privremeno isključiti WP Rocket
- Jednostavna rešenja za popravku koda
- Kako automatski primeniti popravke
- Šta učiniti ako je sajt već pao
Ako si nedavno ažurirao WordPress na verziju 7.1 i imaš instaliran WP Rocket, a sajt ti je iznenada prazan sa porukom “There has been a critical error on this website”, nisi jedini. Naišli smo na ovaj problem na nekoliko sajtova koje održavamo, i evo šta stoji iza toga i kako se rešava, sam ili uz naš gotov fix.
Šta se tačno dešava
Posetilac otvori bilo koju stranicu sajta i umesto sadržaja dobije belu stranicu sa opštom porukom o grešci. Isto se dešava i u administraciji, pa ni ti ne možeš da uđeš u wp-admin. Server u pozadini vraća HTTP 500. Ako pogledaš error log, videćeš nešto slično ovome:
PHP Fatal error: Uncaught TypeError: substr(): Argument #1 ($string)
must be of type string, int given in
.../wp-content/plugins/wp-rocket/inc/ThirdParty/Plugins/CDN/Cloudflare.php
Sajt pada odmah, pre nego što uopšte počne da učitava stranicu, tako da uobičajeni trikovi tipa gašenja keš plugina iz admina neće pomoći, jer ne možeš ni da uđeš u admin.
Zašto se ovo dešava
WordPress 7.1 je promenio način na koji interno identifikuje funkcije zakačene na hook-ove (tehnički, prešao je sa spl_object_hash() na spl_object_id()). Ranije je taj identifikator uvek bio tekst, sada je broj. PHP automatski takve brojeve, kad se koriste kao ključevi u nizu, tretira kao cele brojeve umesto teksta.
WP Rocket na jednom mestu u svom kodu (u delu koji se stara o Cloudflare integraciji) uzima taj ključ i direktno ga prosleđuje funkciji substr(), bez provere da li je tekst. Na PHP 8 to baca grešku tipa, i cela greška se dešava toliko rano da obori kompletan sajt.
Bitno je da se ovo javlja samo kada su ispunjena oba uslova: WordPress 7.1 i WP Rocket bilo koje verzije do 3.20.5 (uključujući i najnoviju, proverili smo). Ako nemaš WP Rocket, ovo te se ne tiče. Ako imaš WP Rocket ali si ostao na WordPress-u 7.0.x, sajt trenutno radi, ali će pasti čim ažuriraš jezgro.
Da li si ugrožen
Proveri dva podatka na svom sajtu:
- Verzija WordPress-a, u wp-admin pod Kontrolna tabla > Ažuriranja, ili preko
wp core versionako imaš WP-CLI pristup. - Da li je WP Rocket aktivan, pod Dodaci.
Ako imaš oba, WordPress 7.1 i aktivan WP Rocket, sajt će pasti čim se dogodi ono što pokrene taj deo koda. U našem testiranju to nije bilo garantovano na svakom učitavanju stranice, zavisi od redosleda kojim se drugi delovi koda registruju, ali smo videli da se dešava na produkcionim sajtovima, i kad se desi, sajt je potpuno nedostupan dok se ne popravi ručno preko servera.
Rešenje 1: ugasi WP Rocket privremeno
Najbrže i najsigurnije rešenje ako ti je sajt već pao. Preko FTP-a ili File Manager-a u svom hosting panelu, uđi u wp-content/plugins/ i preimenuj folder wp-rocket u nešto drugo, na primer wp-rocket-off. WordPress će automatski deaktivirati plugin i sajt će opet raditi, samo bez keširanja iz WP Rocketa dok ne primeniš popravku ispod.
Rešenje 2: primeni popravku
Popravka je jedna linija koda: ključ se prvo pretvori u tekst pre nego što se prosledi funkciji substr(). Evo tačne izmene:
// Fajl: wp-content/plugins/wp-rocket/inc/ThirdParty/Plugins/CDN/Cloudflare.php
// Staro:
if ( substr( $key, - strlen( $method ) ) !== $method ) {
// Novo:
if ( substr( (string) $key, - strlen( $method ) ) !== $method ) {
Problem sa ručnim menjanjem fajla je što se izmena briše svaki put kad se WP Rocket ažurira, pa je treba raditi ponovo. Zato smo napravili mali dodatak koji ovo radi automatski, i sam se pobrine da popravka ostane primenjena i posle svakog ažuriranja WP Rocketa, dok zvanična zakrpa ne izađe:
<?php
/**
* Plugin Name: WP Rocket, popravka za WordPress 7.1
* Description: Sam popravlja gresku koja obara sajt kada je WordPress azuriran na 7.1 a instaliran je WP Rocket.
* Version: 1.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
add_action( 'admin_init', 'sm_wp71_wprocket_patch' );
add_action( 'upgrader_process_complete', 'sm_wp71_wprocket_patch' );
function sm_wp71_wprocket_patch() {
$file = WP_PLUGIN_DIR . '/wp-rocket/inc/ThirdParty/Plugins/CDN/Cloudflare.php';
if ( ! file_exists( $file ) || ! is_readable( $file ) || ! is_writable( $file ) ) {
return;
}
$contents = file_get_contents( $file );
if ( false === $contents || strpos( $contents, '(string) $key' ) !== false ) {
return;
}
$patched = preg_replace( '/substr(s*$keys*,/', 'substr( (string) $key,', $contents );
if ( null === $patched || $patched === $contents ) {
return;
}
@copy( $file, $file . '.bak-' . gmdate( 'Ymd-His' ) );
file_put_contents( $file, $patched );
}
Ovo možeš da iskoristiš na dva načina:
- Kao mu-plugin. Sačuvaj kod iznad kao fajl, na primer
wp-rocket-wp71-fix.php, i ubaci ga preko FTP-a uwp-content/mu-plugins/(napravi taj folder ako ne postoji). Mu-pluginovi se učitavaju automatski, bez potrebe da ih aktiviraš, i ne prikazuju se na listi dodataka. - Kao običan plugin. Isti fajl možeš da staviš u
wp-content/plugins/i aktiviraš ga ručno kao svaki drugi dodatak, ili ga postaviš kroz plugin za snippet-e (npr. WPCode, Code Snippets) kao PHP snippet koji se izvršava naadmin_init.
Šta ako sajt već ne radi
Ako je sajt već pao, redosled je: prvo ugasi WP Rocket (Rešenje 1) da sajt ponovo proradi, zatim primeni popravku, pa vrati WP Rocket nazad tako što ćeš mu vratiti originalno ime foldera.