WordPress fără cap: suișurile și coborâșurile creării unui WordPress decuplat

Publicat: 2022-03-10
Rezumat rapid ↬ Toată lumea știe că, dacă un site web este lent, utilizatorii îl vor abandona. Multe studii demonstrează legătura dintre performanța site-ului și ratele de conversie. În acest articol, Denis Zoljom ne împărtășește experiența și elementele de bază ale creării unui WordPress decuplat.

WordPress a parcurs un drum lung de la început ca un simplu instrument de scriere pe blog. După 15 ani, a devenit alegerea CMS numărul unu pentru dezvoltatori și non-dezvoltatori deopotrivă. WordPress alimentează acum aproximativ 30% din primele 10 milioane de site-uri de pe web.

De când API-ul REST a fost inclus în nucleul WordPress, dezvoltatorii îl pot experimenta și utiliza într-un mod decuplat, adică scriind partea front-end folosind cadre sau biblioteci JavaScript. La Infinum, folosim (și încă mai folosim) WordPress într-un mod „clasic”: PHP pentru frontend, precum și pentru backend. După un timp, am vrut să dăm o încercare abordării decuplate. În acest articol, voi împărtăși o privire de ansamblu asupra a ceea ce am vrut să realizăm și a ceea ce am întâlnit în timp ce încercam să ne implementăm obiectivele.

Există mai multe tipuri de proiecte care pot beneficia de această abordare. De exemplu, site-urile de prezentare simple sau site-urile care folosesc WordPress ca backend sunt principalii candidați pentru abordarea decuplată.

În ultimii ani, industria a început, din fericire, să acorde mai multă atenție performanței. Cu toate acestea, fiind o piesă software inclusivă și versatilă ușor de utilizat, WordPress vine cu o multitudine de opțiuni care nu sunt neapărat utilizate în fiecare proiect. Drept urmare, performanța site-ului poate avea de suferit.

Lectură recomandată : Cum să utilizați hărțile termice pentru a urmări clicurile pe site-ul dvs. WordPress

Dacă timpii lungi de răspuns pe site vă țin treaz noaptea, acesta este o instrucțiune pentru dvs. Voi acoperi elementele de bază ale creării unui WordPress decuplat și câteva lecții învățate, inclusiv:

  1. Semnificația unui „WordPress decuplat”
  2. Lucrul cu API-ul REST WordPress implicit
  3. Îmbunătățirea performanței cu abordarea JSON decuplată
  4. Preocupările legate de securitate
Mai multe după săritură! Continuați să citiți mai jos ↓

Deci, ce este exact un WordPress decuplat?

Când vine vorba de modul în care este programat WordPress, un lucru este sigur: nu urmează modelul de design M odel -View- C onttroller (MVC) cu care mulți dezvoltatori sunt familiarizați. Din cauza istoriei sale și pentru că este un fel de furcă a unei vechi platforme de blogging numită „b2” (mai multe detalii aici), este în mare parte scrisă într-un mod procedural (folosind cod bazat pe funcții). Dezvoltatorii de bază WordPress au folosit un sistem de cârlige care a permis altor dezvoltatori să modifice sau să extindă anumite funcționalități.

Este un sistem all-in-one care este echipat cu o interfață de administrare funcțională; gestionează conexiunea la baza de date și are expuse o grămadă de API-uri utile care se ocupă de autentificarea utilizatorilor, rutarea și multe altele.

Dar, mulțumită API-ului REST, puteți separa backend-ul WordPress ca un fel de model și controler împreună care se ocupă de manipularea datelor și interacțiunea cu bazele de date și puteți utiliza Controlerul API REST pentru a interacționa cu un strat de vizualizare separat folosind diferite puncte finale API. Pe lângă separarea MVC, putem (din motive de securitate sau îmbunătățiri de viteză) să plasăm aplicația JS pe un server separat, ca în schema de mai jos:

Imagine care înfățișează diagrama WordPress decuplată cu o parte PHP și JS separate
Diagrama WordPress decuplată. (Previzualizare mare)

Avantajele utilizării abordării decuplate

Un lucru pentru care ați putea dori să utilizați această abordare este pentru a asigura o separare a preocupărilor. Interfața și backend-ul interacționează prin punctele finale; fiecare poate fi pe serverul său separat, care poate fi optimizat special pentru fiecare sarcină respectivă, adică rulând separat o aplicație PHP și rulând o aplicație Node.js.

Separând frontend-ul de backend, este mai ușor să îl reproiectați în viitor, fără a schimba CMS-ul. De asemenea, dezvoltatorilor front-end trebuie să le pese doar ce să facă cu datele pe care le oferă backend-ul. Acest lucru le permite să devină creativi și să folosească biblioteci moderne precum ReactJS, Vue sau Angular pentru a oferi aplicații web foarte dinamice. De exemplu, este mai ușor să construiți o aplicație web progresivă atunci când utilizați bibliotecile menționate mai sus.

Un alt avantaj se reflectă în securitatea site-ului. Exploatarea site-ului web prin backend devine mai dificilă, deoarece este în mare parte ascuns publicului.

Lectură recomandată : Securitatea WordPress ca proces

Deficiențe ale utilizării abordării decuplate

În primul rând, a avea un WordPress decuplat înseamnă a menține două instanțe separate:

  1. WordPress pentru backend;
  2. O aplicație front-end separată, inclusiv actualizări de securitate în timp util.

În al doilea rând, unele dintre bibliotecile front-end au o curbă de învățare mai abruptă. Fie va dura mult timp pentru a învăța o nouă limbă (dacă sunteți obișnuit doar cu HTML și CSS pentru șabloane), fie va fi necesar să aduceți experți JavaScript suplimentari la proiect.

În al treilea rând, prin separarea front-end-ului, pierzi puterea editorului WYSIWYG și nici butonul „Previzualizare live” din WordPress nu funcționează.

Lucrul cu API-ul REST WordPress

Înainte de a aprofunda codul, mai multe lucruri despre WordPress REST API. Întreaga putere a API-ului REST în WordPress a venit cu versiunea 4.7 pe 6 decembrie 2016.

Ceea ce vă permite WordPress REST API este să interacționați cu instalarea dvs. WordPress de la distanță, trimițând și primind obiecte JSON.

Stabilirea unui proiect

Deoarece vine la pachet cu cea mai recentă instalare WordPress, vom lucra la tema Twenty Seventeen. Lucrez la Varying Vagrant Vagrants și am creat un site de testare cu o adresă URL https://dev.wordpress.test/ . Această adresă URL va fi folosită pe tot parcursul articolului. Vom importa, de asemenea, postări din depozitul echipelor de revizuire a temelor wordpress.org, astfel încât să avem câteva date de testare cu care să lucrăm. Dar mai întâi, ne vom familiariza cu lucrul cu punctele finale implicite, apoi ne vom crea propriul punct final personalizat.

Accesați punctul final REST implicit

După cum am menționat deja, WordPress vine cu mai multe puncte finale încorporate pe care le puteți examina accesând ruta /wp-json/ :

 https://dev.wordpress.test/wp-json/

Fie punând această adresă URL direct în browser, fie adăugând-o în aplicația poștaș, veți obține un răspuns JSON de la WordPress REST API care arată cam așa:

 { "name": "Test dev site", "description": "Just another WordPress site", "url": "https://dev.wordpress.test", "home": "https://dev.wordpress.test", "gmt_offset": "0", "timezone_string": "", "namespaces": [ "oembed/1.0", "wp/v2" ], "authentication": [], "routes": { "/": { "namespace": "", "methods": [ "GET" ], "endpoints": [ { "methods": [ "GET" ], "args": { "context": { "required": false, "default": "view" } } } ], "_links": { "self": "https://dev.wordpress.test/wp-json/" } }, "/oembed/1.0": { "namespace": "oembed/1.0", "methods": [ "GET" ], "endpoints": [ { "methods": [ "GET" ], "args": { "namespace": { "required": false, "default": "oembed/1.0" }, "context": { "required": false, "default": "view" } } } ], "_links": { "self": "https://dev.wordpress.test/wp-json/oembed/1.0" } }, ... "wp/v2": { ...

Deci, pentru a obține toate postările de pe site-ul nostru utilizând REST, ar trebui să mergem la https://dev.wordpress.test/wp-json/wp/v2/posts . Observați că wp/v2/ marchează punctele finale rezervate, cum ar fi postări, pagini, media, taxonomii, categorii și așa mai departe.

Deci, cum adăugăm un punct final personalizat?

Creați un punct final REST personalizat

Să presupunem că vrem să adăugăm un punct final nou sau un câmp suplimentar la punctul final existent. Există mai multe moduri în care putem face asta. În primul rând, se poate face automat când se creează un tip de postare personalizat. De exemplu, dorim să creăm un punct final de documentare. Să creăm un mic plugin de testare. Creați un folder de documentație de testare în folderul wp-content/plugins și adăugați fișierul documentation.php care arată astfel:

 <?php /** * Test plugin * * @since 1.0.0 * @package test_plugin * * @wordpress-plugin * Plugin Name: Test Documentation Plugin * Plugin URI: * Description: The test plugin that adds rest functionality * Version: 1.0.0 * Author: Infinum <[email protected]> * Author URI: https://infinum.co/ * License: GPL-2.0+ * License URI: https://www.gnu.org/licenses/gpl-2.0.txt * Text Domain: test-plugin */ namespace Test_Plugin; // If this file is called directly, abort. if ( ! defined( 'WPINC' ) ) { die; } /** * Class that holds all the necessary functionality for the * documentation custom post type * * @since 1.0.0 */ class Documentation { /** * The custom post type slug * * @var string * * @since 1.0.0 */ const PLUGIN_NAME = 'documentation-plugin'; /** * The custom post type slug * * @var string * * @since 1.0.0 */ const POST_TYPE_SLUG = 'documentation'; /** * The custom taxonomy type slug * * @var string * * @since 1.0.0 */ const TAXONOMY_SLUG = 'documentation-category'; /** * Register custom post type * * @since 1.0.0 */ public function register_post_type() { $args = array( 'label' => esc_html( 'Documentation', 'test-plugin' ), 'public' => true, 'menu_position' => 47, 'menu_icon' => 'dashicons-book', 'supports' => array( 'title', 'editor', 'revisions', 'thumbnail' ), 'has_archive' => false, 'show_in_rest' => true, 'publicly_queryable' => false, ); register_post_type( self::POST_TYPE_SLUG, $args ); } /** * Register custom tag taxonomy * * @since 1.0.0 */ public function register_taxonomy() { $args = array( 'hierarchical' => false, 'label' => esc_html( 'Documentation tags', 'test-plugin' ), 'show_ui' => true, 'show_admin_column' => true, 'update_count_callback' => '_update_post_term_count', 'show_in_rest' => true, 'query_var' => true, ); register_taxonomy( self::TAXONOMY_SLUG, [ self::POST_TYPE_SLUG ], $args ); } } $documentation = new Documentation(); add_action( 'init', [ $documentation, 'register_post_type' ] ); add_action( 'init', [ $documentation, 'register_taxonomy' ] );

Înregistrând noul tip de postare și taxonomie și setând argumentul show_in_rest la true , WordPress a creat automat o rută REST în spațiul de nume /wp/v2/ . Acum aveți disponibile puncte finale https://dev.wordpress.test/wp-json/wp/v2/documentation și https://dev.wordpress.test/wp-json/wp/v2/documentation-category . Dacă adăugăm o postare în postarea personalizată a documentației nou creată care merge la https://dev.wordpress.test/?post_type=documentation , ne va oferi un răspuns care arată astfel:

 [ { "id": 4, "date": "2018-06-11T19:48:51", "date_gmt": "2018-06-11T19:48:51", "guid": { "rendered": "https://dev.wordpress.test/?post_type=documentation&p=4" }, "modified": "2018-06-11T19:48:51", "modified_gmt": "2018-06-11T19:48:51", "slug": "test-documentation", "status": "publish", "type": "documentation", "link": "https://dev.wordpress.test/documentation/test-documentation/", "title": { "rendered": "Test documentation" }, "content": { "rendered": "

Acesta este o parte din conținutul documentației

\n", „protejat”: fals }, „featured_media”: 0, "șablon": "", „categoria-documentație”: [ 2 ], „_links”: { "de sine": [ { „href”: „https://dev.wordpress.test/wp-json/wp/v2/documentation/4” } ], "Colectie": [ { „href”: „https://dev.wordpress.test/wp-json/wp/v2/documentation” } ], "despre": [ { „href”: „https://dev.wordpress.test/wp-json/wp/v2/types/documentation” } ], "versiunea istorică": [ { „href”: „https://dev.wordpress.test/wp-json/wp/v2/documentation/4/revisions” } ], "wp:attachment": [ { „href”: „https://dev.wordpress.test/wp-json/wp/v2/media?parent=4” } ], „wp:term”: [ { "taxonomie": "categorie-documentație", „încorporabil”: adevărat, „href”: „https://dev.wordpress.test/wp-json/wp/v2/documentation-category?post=4” } ], "curie": [ { "nume": "wp", "href": "https://api.w.org/{rel}", „șablonat”: adevărat } ] } } ]

Acesta este un punct de plecare excelent pentru aplicația noastră cu o singură pagină. Un alt mod în care putem adăuga un punct final personalizat este prin conectarea la cârligul rest_api_init și să creăm noi înșine un punct final. Să adăugăm o rută custom-documentation care este puțin diferită de cea pe care am înregistrat-o. Încă lucrând în același plugin, putem adăuga:

 /** * Create a custom endpoint * * @since 1.0.0 */ public function create_custom_documentation_endpoint() { register_rest_route( self::PLUGIN_NAME . '/v1', '/custom-documentation', array( 'methods' => 'GET', 'callback' => [ $this, 'get_custom_documentation' ], ) ); } /** * Create a callback for the custom documentation endpoint * * @return string JSON that indicates success/failure of the update, * or JSON that indicates an error occurred. * @since 1.0.0 */ public function get_custom_documentation() { /* Some permission checks can be added here. */ // Return only documentation name and tag name. $doc_args = array( 'post_type' => self::POST_TYPE_SLUG, 'post_status' => 'publish', 'perm' => 'readable' ); $query = new \WP_Query( $doc_args ); $response = []; $counter = 0; // The Loop if ( $query->have_posts() ) { while ( $query->have_posts() ) { $query->the_post(); $post_id = get_the_ID(); $post_tags = get_the_terms( $post_id, self::TAXONOMY_SLUG ); $response[ $counter ]['title'] = get_the_title(); foreach ( $post_tags as $tags_key => $tags_value ) { $response[ $counter ]['tags'][] = $tags_value->name; } $counter++; } } else { $response = esc_html__( 'There are no posts.', 'documentation-plugin' ); } /* Restore original Post Data */ wp_reset_postdata(); return rest_ensure_response( $response ); }

Și conectați metoda create_custom_documentation_endpoint() la cârligul rest_api_init , așa:

 add_action( 'rest_api_init', [ $documentation, 'create_custom_documentation_endpoint' ] );

Aceasta va adăuga o rută personalizată în https://dev.wordpress.test/wp-json/documentation-plugin/v1/custom-documentation , apelarea returnând răspunsul pentru acea rută.

 [{ "title": "Another test documentation", "tags": ["Another tag"] }, { "title": "Test documentation", "tags": ["REST API", "test tag"] }]

Există o mulțime de alte lucruri pe care le puteți face cu REST API (puteți găsi mai multe detalii în manualul REST API).

Evitați timpi lungi de răspuns atunci când utilizați API-ul REST implicit

Pentru oricine a încercat să construiască un site WordPress decuplat, acesta nu este un lucru nou - API-ul REST este lent.

Echipa mea și cu mine am întâlnit pentru prima dată ciudatul API REST cu întârziere WordPress pe un site client (nu decuplat), unde am folosit punctele finale personalizate pentru a obține lista de locații pe o hartă Google, alături de alte meta informații create folosind Advanced Custom Fields Pro conecteaza. S-a dovedit că timpul pentru primul octet (TTFB) - care este folosit ca o indicație a capacității de răspuns a unui server web sau a unei alte resurse de rețea - a durat mai mult de 3 secunde.

După un pic de investigare, ne-am dat seama că apelurile implicite REST API au fost de fapt foarte lente, mai ales când am „încărcat” site-ul cu pluginuri suplimentare. Deci, am făcut un mic test. Am instalat câteva plugin-uri populare și am întâlnit câteva rezultate interesante. Aplicația poștaș a dat timp de încărcare de 1,97 s pentru 41,9 KB de dimensiune de răspuns. Timpul de încărcare a Chrome a fost de 1,25 s (TTFB a fost de 1,25 s, conținutul a fost descărcat în 3,96 ms). Doar pentru a prelua o listă simplă de postări. Fără taxonomie, fără date despre utilizator, fără meta câmpuri suplimentare.

De ce s-a întâmplat asta?

Se pare că accesarea REST API pe WordPress implicit va încărca întregul nucleu WordPress pentru a servi punctele finale, chiar dacă nu este folosit. De asemenea, cu cât adăugați mai multe plugin-uri, cu atât lucrurile devin mai rău. Controlerul REST implicit WP_REST_Controller este o clasă foarte mare care face mult mai mult decât este necesar atunci când construiește o pagină web simplă. Se ocupă de înregistrarea rutelor, verificări de permisiuni, crearea și ștergerea articolelor și așa mai departe.

Există două soluții comune pentru această problemă:

  1. Interceptați încărcarea pluginurilor și împiedicați încărcarea lor pe toate atunci când aveți nevoie să furnizați un răspuns REST simplu;
  2. Încărcați numai minimumul de WordPress și stocați datele într-un tranzitor, din care apoi obținem datele folosind o pagină personalizată.

Îmbunătățirea performanței cu abordarea JSON decuplată

Când lucrați cu site-uri de prezentare simple, nu aveți nevoie de toate funcționalitățile pe care vi le oferă REST API. Desigur, aici este esențială o bună planificare. Chiar nu doriți să vă construiți site-ul fără API-ul REST și apoi să spuneți peste câțiva ani că doriți să vă conectați la site-ul dvs. sau poate să creați o aplicație mobilă care trebuie să utilizeze funcționalitatea API-ului REST. Tu?

Din acest motiv, am folosit două funcții WordPress care vă pot ajuta atunci când furnizați date JSON simple:

  • Transients API pentru stocarea în cache,
  • Se încarcă WordPress minim necesar folosind constanta SHORTINIT .

Crearea unui punct final simplu de pagini decuplate

Să creăm un mic plugin care să demonstreze efectul despre care vorbim. Mai întâi, adăugați un fișier wp-config-simple.php în pluginul dvs. json-transient care arată astfel:

 <?php /** * Create simple wp configuration for the routes * * @since 1.0.0 * @package json-transient */ define( 'SHORTINIT', true ); $parse_uri = explode( 'wp-content', $_SERVER['SCRIPT_FILENAME'] ); require_once filter_var( $parse_uri[0] . 'wp-load.php', FILTER_SANITIZE_STRING );

define( 'SHORTINIT', true ); va împiedica încărcarea majorității fișierelor de bază WordPress, așa cum se poate vedea în fișierul wp-settings.php .

Este posibil să avem încă nevoie de unele dintre funcționalitățile WordPress, așa că putem solicita fișierul (cum ar fi wp-load.php ) manual. Deoarece wp-load.php se află în rădăcina instalării noastre WordPress, îl vom prelua obținând calea fișierului nostru folosind $_SERVER['SCRIPT_FILENAME'] și apoi explodând acel șir cu șirul wp-content . Aceasta va returna o matrice cu două valori:

  1. Rădăcina instalației noastre;
  2. Restul căii fișierului (care nu ne interesează).

Rețineți că folosim instalarea implicită a WordPress, și nu una modificată, cum ar fi, de exemplu, în boilerplate Bedrock, care împarte WordPress într-o organizație diferită de fișiere.

În cele din urmă, avem nevoie de fișierul wp-load.php , cu puțină igienizare, pentru securitate.

În fișierul nostru init.php , vom adăuga următoarele:

* Author URI: https://infinum.co/ * License: GPL-2.0+ * License URI: https://www.gnu.org/licenses/gpl-2.0.txt * Text Domain: json-transient */ namespace Json_Transient; // If this file is called directly, abort. if ( ! defined( 'WPINC' ) ) { die; } class Init { /** * Get the array of allowed types to do operations on. * * @return array * * @since 1.0.0 */ public function get_allowed_post_types() { return array( 'post', 'page' ); } /** * Check if post type is allowed to be save in transient. * * @param string $post_type Get post type. * @return boolean * * @since 1.0.0 */ public function is_post_type_allowed_to_save( $post_type = null ) { if( ! $post_type ) { return false; } $allowed_types = $this->get_allowed_post_types(); if ( in_array( $post_type, $allowed_types, true ) ) { return true; } return false; } /** * Get Page cache name for transient by post slug and type. * * @param string $post_slug Page Slug to save. * @param string $post_type Page Type to save. * @return string * * @since 1.0.0 */ public function get_page_cache_name_by_slug( $post_slug = null, $post_type = null ) { if( ! $post_slug || ! $post_type ) { return false; } $post_slug = str_replace( '__trashed', '', $post_slug ); return 'jt_data_' . $post_type . '_' . $post_slug; } /** * Get full post data by post slug and type. * * @param string $post_slug Page Slug to do Query by. * @param string $post_type Page Type to do Query by. * @return array * * @since 1.0.0 */ public function get_page_data_by_slug( $post_slug = null, $post_type = null ) { if( ! $post_slug || ! $post_type ) { return false; } $page_output = ''; $args = array( 'name' => $post_slug, 'post_type' => $post_type, 'posts_per_page' => 1, 'no_found_rows' => true ); $the_query = new \WP_Query( $args ); if ( $the_query->have_posts() ) { while ( $the_query->have_posts() ) { $the_query->the_post(); $page_output = $the_query->post; } wp_reset_postdata(); } return $page_output; } /** * Return Page in JSON format * * @param string $post_slug Page Slug. * @param string $post_type Page Type. * @return json * * @since 1.0.0 */ public function get_json_page( $post_slug = null, $post_type = null ) { if( ! $post_slug || ! $post_type ) { return false; } return wp_json_encode( $this->get_page_data_by_slug( $post_slug, $post_type ) ); } /** * Update Page to transient for caching on action hooks save_post. * * @param int $post_id Saved Post ID provided by action hook. * * @since 1.0.0 */ public function update_page_transient( $post_id ) { $post_status = get_post_status( $post_id ); $post = get_post( $post_id ); $post_slug = $post->post_name; $post_type = $post->post_type; $cache_name = $this->get_page_cache_name_by_slug( $post_slug, $post_type ); if( ! $cache_name ) { return false; } if( $post_status === 'auto-draft' || $post_status === 'inherit' ) { return false; } else if( $post_status === 'trash' ) { delete_transient( $cache_name ); } else { if( $this->is_post_type_allowed_to_save( $post_type ) ) { $cache = $this->get_json_page( $post_slug, $post_type ); set_transient( $cache_name, $cache, 0 ); } } } } $init = new Init(); add_action( 'save_post', [ $init, 'update_page_transient' ] );

Metodele de ajutor din codul de mai sus ne vor permite să facem ceva memorare în cache:

  • get_allowed_post_types()
    Această metodă permite tipurilor de postări să știe că dorim să activăm afișarea în „punctul final” personalizat. Puteți extinde acest lucru și pluginul pe care l-am făcut de fapt această metodă să fie filtrabilă, astfel încât să puteți utiliza doar un filtru pentru a adăuga elemente suplimentare.
  • is_post_type_allowed_to_save()
    Această metodă pur și simplu verifică pentru a vedea dacă tipul de postare de la care încercăm să preluăm datele se află în matricea permisă specificată de metoda anterioară.
  • get_page_cache_name_by_slug()
    Această metodă va returna numele tranzitorului de la care vor fi preluate datele.
  • get_page_data_by_slug()
    Această metodă este metoda care va efectua WP_Query pe post prin tipul său slug și post și va returna conținutul matricei de post pe care îl vom converti cu JSON folosind metoda get_json_page() .
  • update_page_transient()
    Acesta va fi rulat pe cârligul save_post și va suprascrie tranzitorii din baza de date cu datele JSON ale postării noastre. Această ultimă metodă este cunoscută sub numele de „metoda de cache a cheilor”.

Să explicăm tranzitorii mai în profunzime.

API-ul Tranzitori

API-ul Tranzitori este folosit pentru a stoca date în tabelul de opțiuni al bazei de date WordPress pentru o anumită perioadă de timp. Este o memorie cache a obiectelor persistentă, ceea ce înseamnă că stocați un obiect, de exemplu, rezultate ale interogărilor mari și lente sau pagini întregi care pot fi persistente pe parcursul încărcărilor de pagină. Este similar cu WordPress Object Cache obișnuit, dar spre deosebire WP_Cache , tranzitorii vor persista datele în încărcările paginii, unde WP_Cache (stocarea datelor în memorie) va păstra datele doar pe durata unei solicitări.

Este un magazin cheie-valoare, ceea ce înseamnă că putem prelua cu ușurință și rapid datele dorite, similar cu ceea ce fac in-memory caching systems precum Memcached sau Redis. Diferența este că, de obicei, ar trebui să le instalați separat pe server (ceea ce poate fi o problemă pe serverele partajate), în timp ce tranzitorii sunt încorporați cu WordPress.

După cum s-a menționat pe pagina sa Codex - tranzitorii sunt în mod inerent accelerați prin memorarea în cache a pluginurilor. Deoarece pot stoca tranzitorii în memorie în loc de o bază de date. Regula generală este că nu ar trebui să presupunem că tranzitoriul este întotdeauna prezent în baza de date - de aceea este o practică bună să verificați existența acestuia înainte de a-l prelua.

 $transient_name = get_transient( 'transient_name' ); if ( $transient_name === false ) { set_transient( 'transient_name', $transient_data, $transient_expiry ); }

Îl puteți folosi fără expirare (cum facem noi), și de aceea am implementat un fel de „busting cache-busting” la salvare post. Pe lângă toate funcționalitățile grozave pe care le oferă, acestea pot stoca până la 4 GB de date, dar nu vă recomandăm să stocați ceva atât de mare într-un singur câmp de bază de date.

Lectură recomandată : Fiți atenți: funcțiile PHP și WordPress care vă pot face site-ul nesigur

Punct final final: testare și verificare

Ultima piesă a puzzle-ului de care avem nevoie este un „punct final”. Folosesc termenul punct final aici, chiar dacă nu este un punct final, deoarece apelăm direct un anumit fișier pentru a ne prelua rezultatele. Deci putem crea un fișier test.php care arată astfel:

 get_page_cache_name_by_slug( $post_slug, $post_type ) ); // Return error on false. if ( $cache === false ) { wp_send_json( 'Error, the page does not exist or it is not cached correctly. Please try rebuilding cache and try again!' ); } // Decode json for output. wp_send_json( json_decode( $cache ) );

Dacă mergem la https://dev.wordpress.test/wp-content/plugins/json-transient/test.php , vom vedea acest mesaj:

Eroare, pagina slug sau tip lipsește!

Așadar, va trebui să specificăm tipul postării și slug-ul postării. Când mergem acum la https://dev.wordpress.test/wp-content/plugins/json-transient/test.php?slug=hello-world&type=post vom vedea:

Eroare, pagina nu există sau nu este memorată corect în cache. Vă rugăm să încercați să reconstruiți memoria cache și să încercați din nou!

Oh, așteptați! Mai întâi trebuie să re-salvam paginile și postările noastre. Deci, atunci când începi, acest lucru poate fi ușor. Dar dacă aveți deja peste 100 de pagini sau postări, aceasta poate fi o sarcină dificilă. Acesta este motivul pentru care am implementat o modalitate de a șterge tranzitorii în pluginul Conținut JSON decuplat și de a le reconstrui într-un lot.

Dar continuă și salvează din nou postarea Hello World și apoi deschide din nou linkul. Ceea ce ar trebui să aveți acum este ceva care arată astfel:

 { "ID": 1, "post_author": "1", "post_date": "2018-06-26 18:28:57", "post_date_gmt": "2018-06-26 18:28:57", "post_content": "Welcome to WordPress. This is your first post. Edit or delete it, then start writing!", "post_title": "Hello world!", "post_excerpt": "", "post_status": "publish", "comment_status": "open", "ping_status": "open", "post_password": "", "post_name": "hello-world", "to_ping": "", "pinged": "", "post_modified": "2018-06-30 08:34:52", "post_modified_gmt": "2018-06-30 08:34:52", "post_content_filtered": "", "post_parent": 0, "guid": "http:\/\/dev.wordpress.test\/?p=1", "menu_order": 0, "post_type": "post", "post_mime_type": "", "comment_count": "1", "filter": "raw" }

Si asta e. Pluginul pe care l-am creat are mai multe funcționalități suplimentare pe care le puteți folosi, dar pe scurt, așa puteți prelua datele JSON din WordPress, care este mult mai rapid decât folosind API-ul REST.

Înainte și după: Timp de răspuns îmbunătățit

Am efectuat teste în Chrome, unde am putut vedea separat timpul total de răspuns și TTFB. Am testat timpii de răspuns de zece ori la rând: mai întâi fără pluginuri și apoi cu pluginurile adăugate. De asemenea, am testat răspunsul pentru o listă de postări și pentru o singură postare.

Rezultatele testului sunt ilustrate în tabelele de mai jos:

Grafic de comparație care ilustrează timpii de răspuns ale utilizării API-ului REST WordPress față de utilizarea abordării decuplate fără pluginuri adăugate. Abordarea decuplată este de 2 până la 3 ori mai rapidă
Grafic de comparație care ilustrează timpii de răspuns ale utilizării API-ului REST WordPress față de utilizarea abordării decuplate fără pluginuri adăugate. Abordarea decuplată este de 2 până la 3 ori mai rapidă. (Previzualizare mare)
Grafic de comparație care ilustrează timpii de răspuns ale utilizării API-ului REST WordPress față de utilizarea abordării decuplate cu pluginuri adăugate. Abordarea decuplată este de până la 8 ori mai rapidă.
Grafic de comparație care ilustrează timpii de răspuns ale utilizării API-ului REST WordPress față de utilizarea abordării decuplate cu pluginuri adăugate. Abordarea decuplată este de până la 8 ori mai rapidă. (Previzualizare mare)

După cum puteți vedea, diferența este drastică.

Preocupările legate de securitate

Există câteva avertismente la care va trebui să le analizați bine. În primul rând, încărcăm manual fișierele de bază WordPress, ceea ce în lumea WordPress este un mare nu-nu. De ce? Ei bine, pe lângă faptul că preluarea manuală a fișierelor de bază poate fi dificilă (mai ales dacă utilizați instalări nestandard, cum ar fi Bedrock), ar putea pune unele probleme de securitate.

Dacă decideți să utilizați metoda descrisă în acest articol, asigurați-vă că știți cum să vă întăriți securitatea serverului.

Mai întâi, adăugați anteturi HTML ca în fișierul test.php :

 header( 'Access-Control-Allow-Origin: your-front-end-app.url' ); header( 'Content-Type: application/json' );

Primul antet este o modalitate de a ocoli măsura de securitate CORS, astfel încât numai aplicația dvs. frontală să poată prelua conținutul atunci când accesați fișierul specificat.

În al doilea rând, dezactivați traversarea directoarelor aplicației dvs. Puteți face acest lucru modificând setările nginx sau adăugați Options -Indexes la fișierul dvs. .htaccess dacă vă aflați pe un server Apache.

Adăugarea unui token check la răspuns este, de asemenea, o măsură bună care poate preveni accesul nedorit. De fapt, lucrăm la o modalitate de a modifica pluginul nostru JSON decuplat, astfel încât să putem include aceste măsuri de securitate în mod implicit.

O verificare pentru un antet de autorizare trimis de aplicația frontend ar putea arăta astfel:

 if ( ! isset( $_SERVER['HTTP_AUTHORIZATION'] ) ) { return; } $auth_header = $_SERVER['HTTP_AUTHORIZATION'];

Apoi puteți verifica dacă simbolul specific (un secret care este partajat doar de aplicațiile front-end și back-end) este furnizat și corect.

Concluzie

API-ul REST este grozav deoarece poate fi folosit pentru a crea aplicații cu drepturi depline - crearea, preluarea, actualizarea și ștergerea datelor. Dezavantajul folosirii acestuia este viteza sa.

Evident, crearea unei aplicații este diferită de crearea unui site web clasic. Probabil că nu veți avea nevoie de toate pluginurile pe care le-am instalat. Dar dacă aveți nevoie doar de date în scopuri de prezentare, stocarea în cache a datelor și servirea lor într-un fișier personalizat pare soluția perfectă în acest moment, atunci când lucrați cu site-uri decuplate.

S-ar putea să vă gândiți că crearea unui plugin personalizat pentru a accelera timpul de răspuns al site-ului este o exagerare, dar trăim într-o lume în care fiecare secundă contează. Toată lumea știe că, dacă un site web este lent, utilizatorii îl vor abandona. Există multe studii care demonstrează legătura dintre performanța site-ului și ratele de conversie. Dar dacă tot ai nevoie de convingere, Google penalizează site-urile lente.

Metoda explicată în acest articol rezolvă problema vitezei pe care o întâlnește API-ul WordPress REST și vă va oferi un impuls suplimentar atunci când lucrați la un proiect WordPress decuplat. Întrucât suntem în încercarea noastră nesfârșită de a scoate ultima milisecundă din fiecare cerere și răspuns, intenționăm să optimizăm și mai mult pluginul. Între timp, vă rugăm să vă împărtășiți ideile despre accelerarea WordPress decuplat!