get_option() vs get_theme_mod(): De ce una este mai lentă?
Am folosit get_theme_mod()
pentru o perioadă în diverse proiecte ale mele. Am decis să profit de Theme Customization API din WordPress v3.4 odată ce a devenit disponibil, considerând că este un instrument indispensabil pentru clienții mei.
După un timp, am început să observ că site-urile mele deveneau puțin mai lente decât de obicei, iar Customizer-ul în special avea nevoie de mult timp pentru a se încărca. După numeroase încercări în timpul investigației mele, am decis să schimb parametrul type
atunci când înregistrez setările (adică $wp_customize->add_setting()
) din theme_mod
în option
.
După ce am făcut această modificare și am înlocuit toate apelurile get_theme_mod()
cu get_option()
, am observat o creștere foarte semnificativă a vitezei folosind cea din urmă configurație în comparație cu prima, atât în frontend cât și mai ales în Customizer în backend. Am căutat prin codul sursă WordPress încercând să găsesc un răspuns pentru această situație, dar nu am reușit să înțeleg care este problema specifică în acest scenariu.
Orice informații pe care comunitatea le-ar putea oferi cu privire la motivul pentru care get_option()
funcționează semnificativ mai rapid decât get_theme_mod()
ar fi foarte apreciate.
Răspunsul este da, funcțiile theme_mod vor fi mai lente, dar nu semnificativ, iar beneficiile depășesc diferențele.
Setările temei (theme mods) sunt stocate ca opțiuni. Deci, în esență, funcțiile theme_mod sunt wrapper-uri în jurul funcțiilor de opțiuni.
Mai întâi, înțelegeți că setările theme_mod sunt stocate ca un array într-o singură opțiune, asociată numelui temei specifice. Deci, dacă fac asta:
set_theme_mod('aaa',123);
set_theme_mod('bbb',456);
Atunci ceea ce obțin de fapt în baza de date este un singur rând de opțiuni cu numele theme_mods_numeletemei care conține un array serializat cu ('aaa'=>123, 'bbb'=>456) în el.
Acum, get_theme_mod
va fi mai lent pentru că de fapt face două apeluri get_option
. Mai întâi, obține numele temei. Apoi, obține opțiunea theme_mods_numeletemei
. Deci chiar aici avem o pierdere de viteză de 50%. Restul lucrării constă în mare parte în filtre, în sensul că există un apel suplimentar de filtru, dar dacă nu aveți ceva pe acel filtru, acest lucru este cam nesemnificativ.
Rețineți că sistemul de opțiuni stochează datele preluate în cache-ul de obiecte, deci nu se fac mai multe apeluri către baza de date aici. Doar prima utilizare duce la un acces la baza de date.
set_theme_mod
va fi oarecum mai lent pentru că face aceleași două apeluri get options, apoi face încă un apel get_option
pentru a obține din nou numele temei, iar apoi face update_option
cu întregul set de opțiuni acum modificate. Acest lucru provoacă o actualizare a bazei de date, iar faptul că trimite mult mai multe date poate fi într-adevăr cauza unei încetiniri observabile. Actualizarea a câțiva octeți este mai rapidă decât actualizarea unui rând mai mare. Dar nu atât de mult încât să observați, de obicei. Doar dacă aveți o grămadă de setări...
Funcțiile theme_mod sunt probabil necesare pentru o optimizare generală, cu siguranță, dar tot ar trebui să le folosiți în loc de get_option și altele din cauza temelor copil.
Problema cu utilizarea directă a rândurilor de opțiuni este că le utilizați direct și folosiți nume specifice de chei pentru setările dumneavoastră.
Dacă am o temă numită "AAA" și fac o temă copil a acesteia numită "BBB" pentru utilizare pe un alt site, atunci tema mea "AAA" ar putea folosi o opțiune numită "exemplu". Când actualizez un site și acesta actualizează opțiunea mea, atunci aceeași opțiune se va aplica și temei mele copil. Ce se întâmplă dacă nu am vrut să se întâmple asta? Ce se întâmplă dacă am vrut ca tema copil să folosească un set diferit de opțiuni?
Theme mods, prin includerea numelui real al temei (și nu a unei valori hardcodate) ca parte a cheii, asigură că fiecare "temă" de pe site folosește propriul set de setări. Pot să trec de la una la alta și setările nu se transferă între ele, ele rămân așa cum le-am setat. Mai simplu, mai evident, mai intuitiv.
Și dacă vreo modificare viitoare a nucleului sau un plugin modifică modul în care funcționează theme_mods, atunci veți beneficia automat de aceasta fără nicio modificare. Wrapper-ele vor fi întotdeauna mai lente, acest lucru este inevitabil, este natura wrapper-elor. Cu toate acestea, tot scrieți cod PHP, nu limbaj de mașină. Folosim wrapper-e ca acestea pentru a simplifica lucrurile și a separa funcționalitățile. Temele nu ar trebui să știe sau să le pese cum sunt stocate opțiunile lor în baza de date sau cum funcționează denumirea. Funcțiile theme_mod oferă o soluție mai simplă care este mai curată.

get_theme_mod
este doar un înveliș în jurul funcției get_option
. Teoretic, deoarece reprezintă un strat suplimentar de abstractizare, ar trebui să funcționeze mai lent, dar în practică diferența nu ar trebui să fie suficient de mare pentru a fi observată de om.
Diferențe reale de viteză pot apărea dacă aveți un cod lent atașat la hook-urile theme_mod.

Nu este un wrapper. get_theme_mod stochează valoarea într-un array serializat împreună cu toate opțiunile temei într-un rând din tabelul wp_options, cu cheia predeterminată "theme_mods_<nume tema>". get_option stochează valoarea în câmpul option_value al unui rând din tabelul wp_options, cu o cheie pe care o specificați. Altfel spus, get_theme_mod grupează valoarea într-un array serializat cu toate celelalte modificări ale temei; get_option nu face acest lucru.

Ar putea fi ceva legat de Customizer? Observ același lucru ca și OP aici.
Pot confirma că, cu aproximativ 30 de opțiuni, timpul de încărcare al Customizer-ului meu a scăzut de la aproximativ 3 secunde la aproximativ 0,5 secunde când am trecut de la get_theme_mod
la get_option
.
Apelând metodele direct, observ o diferență de 2ms.
(https://gist.github.com/anonymous/d98a46d00d52d40e7dec)
Diferența poate să nu fie vizibilă când compari API-urile direct, dar trebuie să fie ceva în modul în care sunt utilizate în Customizer.

Poți TESTA TIMPUL pentru get_option
(100 de iterații) folosind acest cod (introduce-l în functions.php
sau altundeva):
add_action('wp','My_Test');
function My_Test(){
var_dump(microtime(true));
for ($i=1; $i<100; $i++) { get_option('blogdescription'); }
var_dump(microtime(true));
for ($i=1; $i<100; $i++) { get_theme_mod('blogdescription'); }
var_dump(microtime(true));
exit;
}
Alte considerații
Nu știu dacă face vreo diferență (poate dezvoltatorii WordPress știu mai bine), dar m-am gândit că dacă un site are TRAFIC MARE și la fiecare încărcare de pagină trebuie să obțină sute de opțiuni, ce-ar fi dacă aș grupa mai multe opțiuni într-un singur get_option
? Ca în exemplul următor:
update_option('my_extra_optss', array(
'myNAME' => 'George',
'myAGE' => 43 ));
apoi:
$x = get_option('my_extra_optss');
$x['myNAME'];
$x['myAGE'];
................
va face acest lucru site-ul puțin mai rapid?

TL;DR: Dacă ești dezvoltator de teme, ar trebui să folosești get_theme_mod
Răspuns detaliat:
Dacă ai 100 de apeluri get_option, aceasta va efectua 100 de interogări în baza de date.
Dacă ai 100 de apeluri get_theme_mod, aceasta va efectua doar 1 interogare în baza de date.
De ce? Pentru că toate modificările temei sunt stocate într-un singur rând din baza de date și vor fi apelate o singură dată, în timp ce fiecare opțiune este un rând separat și 100 de apeluri get_option vor rezulta în 100 de interogări la baza de date, ceea ce, desigur, va încetini site-ul tău.
Dacă tema ta are multe opțiuni, folosirea get_theme_mod va reduce semnificativ numărul de interogări la baza de date.
Poți verifica performanța și numărul de interogări folosind Plugin-ul Query Monitor

Acest lucru este ușor incorect. Funcția get_theme_mod folosește get_theme_mods - https://developer.wordpress.org/reference/functions/get_theme_mods/ - care de fapt execută 2 funcții get_option. Deci 100 de apeluri get_theme_mod fac de fapt doar 2 cereri către baza de date ;)
