Ghidul avansat pentru optimizarea performanței WordPress
Publicat: 2022-03-11Astăzi, WordPress alimentează peste 30% din Internet. Este ușor de utilizat, incredibil de popular și nu va merge nicăieri prea curând.
Dar WordPress poate fi lent. Deci cum o optimizezi?
Există o mulțime de articole despre cum să reglați și să optimizați WordPress. De fapt, WordPress însuși oferă un ghid solid despre optimizarea WordPress.
În cea mai mare parte, aceste articole și tutoriale acoperă concepte destul de de bază, dar utile, cum ar fi utilizarea pluginurilor cache, integrarea cu rețelele de livrare de conținut (CDN) și minimizarea solicitărilor. Deși aceste sfaturi sunt extrem de eficiente și chiar necesare, în cele din urmă, ele nu abordează problema de bază: cele mai multe site-uri WordPress lente sunt rezultatul unui cod prost sau ineficient.
Prin urmare, acest articol are scopul în principal de a oferi dezvoltatorilor și companiilor de dezvoltare WordPress câteva îndrumări care îi pot ajuta să abordeze cauzele care stau la baza multor probleme de performanță WordPress.
WordPress oferă multe funcții orientate spre performanță, care sunt adesea trecute cu vederea de către dezvoltatori. Codul care nu folosește aceste funcții poate încetini cele mai simple sarcini, cum ar fi preluarea postărilor. Acest articol detaliază patru soluții posibile, care abordează unele dintre problemele care stau la baza performanței lente WordPress.
Preluare postări
WordPress oferă posibilitatea de a prelua orice fel de postare din baza de date. Există trei moduri de bază de a face acest lucru:
Utilizarea funcției
query_posts()
: Aceasta este o abordare foarte directă, dar problema este că suprascrie interogarea principală, ceea ce ar putea duce la inconveniente. De exemplu, aceasta ar putea fi o problemă dacă am dori să stabilim, la un moment dat, după preluarea postărilor (cum ar fi în interiorulfooter.php
), cu ce fel de pagină avem de-a face. De fapt, documentația oficială are o notă care recomandă împotriva utilizării acestei funcții, deoarece va trebui să apelați o funcție suplimentară pentru a restabili interogarea inițială. În plus, înlocuirea interogării principale va avea un impact negativ asupra timpilor de încărcare a paginii.Folosind funcția
get_posts()
: Aceasta funcționează aproape caquery_posts()
, dar nu modifică interogarea principală. Pe de altă parte,get_posts()
în mod implicit realizează interogarea cu parametrulsuppress_filters
setat latrue
. Acest lucru ar putea duce la inconsecvențe, mai ales dacă folosim filtre legate de interogări în codul nostru, deoarece postările la care nu vă așteptați într-o pagină pot fi returnate de această funcție.Folosind clasa
WP_Query
: În opinia mea, aceasta este cea mai bună modalitate de a prelua postări din baza de date. Nu modifică interogarea principală și este executată în modul ei standard, la fel ca orice altă interogare WordPress.
Dar, indiferent de metoda pe care o folosim pentru a interacționa cu baza de date, există și alte lucruri pe care trebuie să le luăm în considerare.
Limitarea interogării
Ar trebui să specificăm întotdeauna câte postări trebuie să preia interogarea noastră.
Pentru a realiza acest lucru, folosim parametrul posts_per_page
.
WordPress ne permite să indicăm -1 ca valoare posibilă pentru acel parametru, caz în care sistemul va încerca să preia toate postările care îndeplinesc condițiile definite.
Aceasta nu este o practică bună, chiar dacă suntem siguri că vom primi doar câteva rezultate înapoi ca răspuns.
În primul rând, rareori putem fi siguri că obținem doar câteva rezultate înapoi. Și chiar dacă putem, stabilirea fără limită va necesita ca motorul bazei de date să scaneze întreaga bază de date în căutarea potrivirilor.
În schimb, limitarea rezultatelor permite adesea motorului bazei de date să scaneze doar parțial datele, ceea ce se traduce printr-un timp de procesare mai mic și un răspuns mai rapid.
Un alt lucru pe care WordPress îl face în mod implicit, care poate afecta negativ performanța, este că încearcă să aducă postări lipicioase și să calculeze câte rânduri au fost găsite pe interogare.
De multe ori, însă, nu avem nevoie de aceste informații. Adăugarea acestor doi parametri va dezactiva acele caracteristici și va accelera interogarea noastră:
$query = new WP_Query( array( 'ignore_sticky_posts' => true, 'no_found_rows' => true ) );
Excluderea postărilor din interogare
Uneori dorim să excludem anumite postări din interogare. WordPress oferă o modalitate destul de directă de a realiza acest lucru: folosind parametrul post__not_in
. De exemplu:
$posts_to_exclude = array( 1, 2, 3 ); $posts_per_page = 10; $query = new WP_Query( array( 'posts_per_page' => $posts_per_page, 'post__not_in' => $posts_to_exclude ) ); for ( $i = 0; $i < count( $query->posts ); $i++ ) { //do stuff with $query->posts[ $i ] }
Dar, deși acest lucru este destul de simplu, nu este optim, deoarece intern generează o subinterogare. În special în instalațiile mari, acest lucru poate duce la răspunsuri lente. Este mai rapid să lași acea procesare să fie efectuată de interpretul PHP cu câteva modificări simple:
$posts_to_exclude = array( 1, 2, 3 ); $posts_per_page = 10; $query = new WP_Query( array( 'posts_per_page' => $posts_per_page + count( $posts_to_exclude ) ) ); for ( $i = 0; $i < count( $query->posts ) && $i < $posts_per_page; $i++ ) { if ( ! in_array( $query->posts[ $i ]->ID, $posts_to_exclude ) ) { //do stuff with $query->posts[ $i ] } }
Ce am făcut acolo?
Practic, am luat ceva de la motorul bazei de date și am lăsat-o în schimb motorului PHP, care face aceleași lucruri, dar în memorie, ceea ce este mult mai rapid.
Cum?
Mai întâi, am eliminat parametrul post__not_in
din interogare.
Deoarece interogarea ne poate aduce unele postări pe care nu le dorim ca rezultat, am mărit parametrul posts_per_page
. În acest fel, mă asigur că, chiar dacă aș fi avut câteva postări nedorite în răspunsul meu, aș avea cel puțin $posts_per_page
postări dorite acolo.
Apoi, când fac bucla peste postări, le procesez doar pe cele care nu sunt în $posts_to_exclude
.
Evitarea parametrizării complexe
Toate aceste metode de interogare oferă o mare varietate de posibilități de preluare a postărilor: pe categorii, după meta chei sau valori, după dată, după autor etc.
Și, în timp ce această flexibilitate este o caracteristică puternică, ar trebui utilizată cu prudență, deoarece acea parametrizare s-ar putea traduce în îmbinări complexe de tabele și operațiuni costisitoare de baze de date.
În secțiunea următoare, vom schița o modalitate elegantă de a obține în continuare funcționalități similare fără a compromite performanța.
Strângerea maximă a opțiunilor WordPress
API-ul WordPress Options oferă o serie de instrumente pentru a încărca sau salva cu ușurință datele. Este util pentru manipularea unor informații mici, pentru care alte mecanisme pe care le oferă WordPress (cum ar fi postările sau taxonomiile) sunt excesiv de complexe.

De exemplu, dacă dorim să stocăm o cheie de autentificare sau culoarea de fundal a antetului site-ului nostru, opțiunile sunt ceea ce căutăm.
WordPress nu numai că ne oferă funcțiile necesare pentru a le gestiona, dar ne permite și să facem acest lucru în cel mai eficient mod.
Unele dintre opțiuni sunt chiar încărcate direct atunci când sistemul pornește, oferindu-ne astfel un acces mai rapid (când creăm o nouă opțiune, trebuie să luăm în considerare dacă vrem să o încărcăm sau nu automat).
Luați în considerare, de exemplu, un site pe care avem un carusel care afișează știri de ultimă oră specificate în back-end. Primul nostru instinct ar fi să folosim o meta-cheie pentru asta, după cum urmează:
// functions.php add_action( 'save_post', function ( $post_id ) { // For simplicity, we do not include all the required validation before saving // the meta key: checking nonces, checking post type and status, checking // it is not a revision or an autosaving, etc. update_post_meta( $post_id, 'is_breaking_news', ! empty ( $_POST['is_breaking_news'] ) ); } ); // front-page.php $query = new WP_Query( array( 'posts_per_page' => 1, 'meta_key' => 'is_breaking_news' ) ); $breaking_news = $query->posts[0] ?: NULL;
După cum puteți vedea, această abordare este foarte simplă, dar nu este optimă. Acesta va efectua o interogare la baza de date încercând să găsească o postare cu o anumită cheie meta. Am putea folosi o opțiune pentru a obține un rezultat similar:
// functions.php add_action( 'save_post', function ( $post_id ) { // Same comment for post validation if ( ! empty ( $_POST['is_breaking_news'] ) ) update_option( 'breaking_news_id', $post_id ); } ); // front-page.php if ( $breaking_news_id = get_option( 'breaking_news_id' ) ) $breaking_news = get_post( $breaking_news_id ); else $breaking_news = NULL;
Funcționalitatea variază ușor de la un exemplu la altul.
În prima bucată de cod, vom primi întotdeauna cele mai recente știri de ultimă oră, în ceea ce privește data publicării postării.
În al doilea, de fiecare dată când o nouă postare este setată ca știri de ultimă oră, aceasta va suprascrie știrile de ultimă oră anterioare.
Dar pentru că probabil că vrem o postare de știri de ultimă oră la un moment dat, nu ar trebui să fie o problemă.
Și, în cele din urmă, am schimbat o interogare grea de bază de date (folosind WP_Query
cu meta chei) într-o interogare simplă și directă (apelând get_post()
), care este o abordare mai bună și mai performantă.
Am putea, de asemenea, să facem o mică modificare și să folosim tranzitorii în loc de opțiuni.
Tranzitorii funcționează în mod similar, dar ne permit să specificăm un timp de expirare.
De exemplu, pentru știrile de ultimă oră, se potrivește ca o mănușă pentru că nu vrem o postare veche ca știri de ultimă oră, iar dacă lăsăm sarcina de a schimba sau elimină știrile de ultimă oră administratorului, [ea] ar putea uita să facă. aceasta. Deci, cu două modificări simple, adăugăm o dată de expirare:
// functions.php add_action( 'save_post', function ( $post_id ) { // Same comment for post validation // Let's say we want that breaking news for one hour // (3600 = # of seconds in an hour). if ( ! empty ( $_POST['is_breaking_news'] ) ) set_transient( 'breaking_news_id', $post_id, 3600 ); } ); // front-page.php if ( $breaking_news_id = get_transient( 'breaking_news_id' ) ) $breaking_news = get_post( $breaking_news_id ); else $breaking_news = NULL;
Activați memorarea în cache persistentă
WordPress are în mod nativ un mecanism de stocare în cache a obiectelor.
Opțiunile, de exemplu, sunt stocate în cache folosind acel mecanism.
Dar, în mod implicit, memorarea în cache nu este persistentă, ceea ce înseamnă că trăiește doar pe durata unei singure solicitări. Toate datele sunt stocate în cache în memorie, pentru un acces mai rapid, dar sunt disponibile numai în timpul acestei solicitări.
Sprijinirea stocării în cache persistentă necesită instalarea unui plugin de cache persistentă.
Unele plugin-uri cache de pagină completă vin cu un plugin cache persistent inclus (de exemplu W3 Total Cache), dar altele nu și trebuie să-l instalăm separat.
Va depinde de arhitectura platformei noastre, dacă vom folosi fișiere, Memcached sau un alt mecanism pentru a stoca datele din cache, dar ar trebui să profităm de această caracteristică uimitoare.
S-ar putea întreba: „Dacă aceasta este o caracteristică atât de grozavă, de ce WordPress nu o activează implicit”?
Motivul principal este că, în funcție de arhitectura platformei noastre, unele tehnici de cache vor funcționa, iar altele nu.
Dacă ne găzduim site-ul pe serverul nostru distribuit, de exemplu, ar trebui să folosim un sistem cache extern, (cum ar fi un server Memcached), dar dacă site-ul nostru se află pe un singur server, am putea economisi niște bani prin simpla utilizare a sistemului de fișiere a stoca în cache.
Un lucru de care trebuie să luăm în considerare este expirarea memoriei cache. Aceasta este cea mai comună capcană în lucrul cu memorarea în cache persistentă.
Dacă nu abordăm corect această problemă, utilizatorii noștri se vor plânge că nu vor vedea modificările pe care le-au făcut sau că modificările lor au durat prea mult să se aplice.
Uneori ne vom trezi să facem compromisuri între performanță și dinamism, dar chiar și cu aceste obstacole, memorarea în cache persistentă este ceva de care ar trebui să profite practic orice instalare WordPress.
AJAXing cel mai rapid mod
Dacă trebuie să comunicăm prin AJAX cu site-ul nostru, WordPress oferă o oarecare abstractizare în momentul procesării cererii pe partea de server.
Chiar dacă aceste tehnici pot fi folosite la programarea instrumentelor back-end sau a trimiterilor de formulare din front-end, ele ar trebui evitate dacă nu este strict necesar.
Motivul pentru aceasta este că, pentru a folosi aceste mecanisme, suntem obligați să facem o cerere de postare la un fișier aflat în folderul wp-admin
. Majoritatea (dacă nu toate) plugin-urile WordPress de stocare în cache pe pagină completă nu memorează în cache solicitările de postare și nici apelurile către fișierele administratorului.
De exemplu, dacă încărcăm în mod dinamic mai multe postări atunci când utilizatorul derulează pagina noastră de pornire, ar fi mai bine să apelăm direct la o altă pagină de front-end, care va avea avantajele de a fi stocată în cache.
Am putea apoi analiza rezultatele prin JavaScript în browser.
Da, trimitem mai multe date decât avem nevoie, dar câștigăm în ceea ce privește viteza de procesare și timpul de răspuns.
Distrugeți ideea că WordPress este doar lent
Acestea sunt doar câteva sfaturi pe care dezvoltatorii ar trebui să le ia în considerare atunci când codifică pentru WordPress.
Uneori, uităm că pluginul sau tema noastră ar putea avea nevoie să conviețuiască cu alte plugin-uri sau că site-ul nostru poate fi deservit de o companie de găzduire care deservește sute sau mii de alte site-uri cu o bază de date comună.
Ne concentrăm doar pe modul în care ar trebui să funcționeze pluginul și nu pe modul în care se ocupă de acea funcționalitate sau cum să o facem într-un mod eficient.
Din cele de mai sus, este clar că cauzele fundamentale ale performanței slabe în WordPress sunt codul prost și ineficient. Cu toate acestea, WordPress oferă toate funcționalitățile necesare prin diferitele sale API-uri care ne pot ajuta să construim plugin-uri și teme mult mai performante, fără a compromite viteza platformei generale.