Crearea unui plugin WordPress care folosește API-uri de servicii, „De la supă la nuci”

Publicat: 2022-03-10
Rezumat rapid ↬ Un număr tot mai mare de API-uri disponibile public oferă servicii puternice pentru a extinde funcționalitatea aplicațiilor noastre. WordPress este un CMS incredibil de dinamic și flexibil, care alimentează orice, de la bloguri personale mici la site-uri web majore de comerț electronic și tot ce se află între ele. O parte din ceea ce face ca WordPress să fie atât de versatil este sistemul său puternic de pluginuri , care face incredibil de ușor să adăugați funcționalități. Vom parcurge modul în care am creat GitHub Pipeline, un plugin care vă permite să afișați date din API-ul GitHub pe paginile WordPress folosind coduri scurte. Voi da exemple specifice și fragmente de cod, dar luați în considerare tehnica descrisă aici un plan pentru cum să consumați orice API de serviciu cu un plugin. Vom începe de la început, dar se presupune un grad de familiaritate cu WordPress și dezvoltarea pluginurilor și nu vom petrece timp pe subiecte pentru începători, cum ar fi instalarea WordPress sau Composer.

Un număr tot mai mare de API-uri disponibile public oferă servicii puternice pentru a extinde funcționalitatea aplicațiilor noastre. WordPress este un CMS incredibil de dinamic și flexibil, care alimentează orice, de la bloguri personale mici la site-uri web majore de comerț electronic și tot ce se află între ele. O parte din ceea ce face ca WordPress să fie atât de versatil este sistemul său puternic de pluginuri , care face incredibil de ușor să adăugați funcționalități.

Vom parcurge modul în care am creat GitHub Pipeline, un plugin care vă permite să afișați date din API-ul GitHub pe paginile WordPress folosind coduri scurte. Voi da exemple specifice și fragmente de cod, dar luați în considerare tehnica descrisă aici un plan pentru cum să consumați orice API de serviciu cu un plugin.

Citiți suplimentare despre SmashingMag:

  • WordPress Essentials: Cum să creezi un plugin WordPress
  • Cum să implementați pluginuri WordPress cu GitHub utilizând tranzitorii
  • Trei abordări pentru adăugarea câmpurilor configurabile la pluginul dvs

Vom începe de la început, dar se presupune un grad de familiaritate cu WordPress și dezvoltarea pluginurilor și nu vom petrece timp pe subiecte pentru începători, cum ar fi instalarea WordPress sau Composer.

Mai multe după săritură! Continuați să citiți mai jos ↓

O să ai nevoie:

  • un mediu PHP, cu o nouă instalare de WordPress;
  • un cont GitHub (sau alt furnizor de API dacă vrei să improvizezi);
  • Compozitor (recomandat).

Alegerea unui API

Primul pas în scrierea acestui tip de plugin este alegerea unui API. În acest tutorial, vom folosi API-ul GitHub. Dacă vă gândiți să utilizați un alt API, luați în considerare câțiva factori importanți care pot afecta cât de plin de satisfacții va fi proiectul dvs.

Unul dintre primele lucruri la care mă uit este minuțiozitatea și calitatea documentației API. Dacă este rar sau învechit, fiți pregătit să petreceți timp cercetând codul sursă pentru a răspunde la propriile întrebări. De asemenea, luați în considerare cât de matur este API-ul și cât de responsabil l-a editat furnizorul. Nimic nu este mai rău decât să investești timp în a crea ceva grozav, doar ca acesta să se rupă din cauza modificărilor aduse API-ului din amonte. Căutați un sistem de versiuni în adresele URL ale punctelor finale.

 // good https://api.stable.com/v1/user/ // danger https://api.dodgy.com/user/

Cu riscul de a afirma ceea ce este evident, programarea împotriva unui API terță parte implică o relație de încredere și nu toate API-urile sunt create egale.

Cumpărături pentru o bibliotecă

Brandurile consacrate distribuie adesea biblioteci sau SDK-uri pentru a facilita lucrul cu API-ul lor. Dacă nu este cazul, amintiți-vă să cercetați dacă altcineva a scris deja o bibliotecă înainte de a merge și a reinventa roata. Google și GitHub sunt două locuri grozave pentru a începe cercetarea. Numărul de stele sau furculițe de pe GitHub este un bun indiciu al cât de eficientă este o bibliotecă. Vârsta celor mai recente comisioane și/sau numărul de probleme deschise indică cât de activ este menținută. În cazul meu, am avut norocul să găsesc minunatul API PHP GitHub, de la KNP Labs.

Scrie-l pe al tău cu Guzzle

Dacă nu există o bibliotecă satisfăcătoare pentru furnizorul dvs., tot nu ar trebui să începeți de la zero, deoarece instrumente precum Guzzle facilitează mult lucrul cu solicitările HTTP. Guzzle include biblioteca cURL a PHP și elimină multe dintre durerile de cap asociate de obicei cu configurarea și efectuarea manuală a cererilor. Chiar dacă faceți doar una sau două solicitări, aș recomanda totuși să îl utilizați, deoarece vă va face codul mai robust, iar instalarea lui cu Composer este o simplă simplă.

Configurarea pluginului

Vom începe cu scheletul de bază al unui plugin WordPress minimal, un director cu două fișiere. Alegerea unui nume de folder descriptiv și unic este importantă pentru a evita conflictele cu alte plugin-uri. Dacă numele pluginului dvs. este oarecum generic, luați în considerare adăugarea unui prefix unic.

 github-api/ readme.txt github-api.php

readme.txt conține metadatele pentru pluginul dvs. care vor apărea pe wordpress.org dacă decideți să le publicați acolo. Citiți despre publicarea pluginurilor WordPress în documentație sau consultați exemplul cuprinzător readme.txt.

Fișierul PHP conține, de asemenea, câteva metadate în antet, care vor fi folosite pentru a afișa informații despre pluginul dvs. în tabloul de bord. Începeți cu un antet care arată astfel:

 <?php /** Plugin Name: GitHub API description: >- Add GitHub project information using shortcode Version: 1.0 Author: Your Name License: GPLv2 or later Text Domain: github-api */

Din motive de securitate, este, de asemenea, o idee bună să interziceți accesul direct la fișier, astfel:

 defined( 'ABSPATH' ) or die( 'No script kiddies please!' );

În acest moment, pluginul nu va face nimic, dar atunci când copiați fișierele în wp-content/plugins , ar trebui să apară în lista de pluginuri și ar trebui să îl puteți activa.

Pagina cu pluginuri pentru tabloul de bord WordPress
Pagina cu pluginuri pentru tabloul de bord WordPress. (Vezi versiunea mare)

În continuare, vom dori să includem biblioteca care se va ocupa de solicitările API. În următorul exemplu de cod, includem API-ul PHP GitHub al KNP Labs, dar puteți include orice dependență înlocuind knplabs/github-api cu pachetul pe care îl utilizați.

 $ cd wp-content/plugins/github-api $ composer require knplabs/github-api

Acum, structura fișierului dvs. ar trebui să arate după cum urmează:

 github-api/ composer.json composer.lock github-api.php readme.txt vendor/

Acum că fișierele sunt la locul lor, trebuie să cerem vendor/autoload.php care a fost creat când l-ați instalat.

 require_once 'vendor/autoload.php';

Dacă totul a fost configurat corect, ar trebui să puteți instanția o clasă din bibliotecă fără a se produce o eroare fatală.

 $testing = new \Github\Client();

Dar aceasta este doar o modalitate rapidă de a testa dacă dependențele dvs. sunt disponibile. Recomand definirea unei noi clase care extinde biblioteca.

 class MyGithub extends \Github\Client {};

Acest lucru nu este critic, dar vă face codul mai flexibil în câteva moduri. Cel mai evident mod este că puteți modifica sau adăuga funcționalități noi dacă este necesar. Dar, de asemenea, face viața mai ușoară dacă doriți vreodată să schimbați bibliotecile în viitor, deoarece va trebui să faceți modificările într-un singur loc, mai degrabă decât în ​​întregul cod.

Coduri scurte WordPress

Acum este timpul să configurați primul nostru cod scurt, care este un fragment special care vă permite să generați conținut plasându-l într-o postare sau într-o pagină. Dacă sunteți complet nou în ceea ce privește codurile scurte sau doriți o înțelegere mai profundă a modului în care funcționează acestea, consultați documentația oficială a codurilor scurte. În exemplul meu, voi afișa o listă de probleme GitHub oriunde autorul plasează acest cod scurt: [github_issues]

Așa cum am făcut înainte, să începem cu un exemplu minim pentru a ne asigura că shortcode-ul este înregistrat corect înainte de a lucra la efectuarea apelului API.

 function github_issues_func( $atts ) { return "Hello world!"; } add_shortcode( "github_issues", "github_issues_func" );

Acum, dacă publicați o pagină care conține [github_issues] , ar trebui să vedeți „Hello world” când vizitați pagina. Acum că funcționează, să setăm apelul API.

În secțiunea anterioară, am configurat încărcarea automată pentru biblioteca noastră GitHub și am definit propria noastră clasă pentru a o extinde. Acum, putem începe să-l folosim pentru a efectua apeluri API. Deci, îl vom adăuga la funcția de apel invers a codului scurt. Ca o dovadă a conceptului, să preluăm toate problemele din depozitul GitHub Pipeline. Documentația pentru această metodă este disponibilă.

 function github_issues_func( $atts ) { // Instantiate our class $gh = new MyGithub(); // Make the API call to get issues, passing in the GitHub owner and repository $issues = $gh->api('issue')->all('TransitScreen', 'wp-github-pipeline'); // Handle the case when there are no issues if ( empty($issues) ) return "<strong>" . __("No issues to show", 'githup-api') . "</strong>"; // We're going to return a string. First, we open a list. $return = "<ul>"; // Loop over the returned issues foreach( $issues as $issue ) { // Add a list item for each issue to the string // (Feel free to get fancier here) // Maybe make each one a link to the issue issuing $issue['url] ) $return .= "<li>{$issue['title']}</li>"; } // Don't forget to close the list $return .= "</ul>"; return $return; } add_shortcode( 'github_issues', 'github_issues_func' );

Acum ar trebui să puteți vizualiza aceeași pagină pe care am folosit-o mai sus pentru a testa codul scurt și de data aceasta ar trebui să vedeți o listă neordonată de probleme. Dar asteapta! Înainte de a continua, să facem o optimizare, astfel încât codul nostru să fie mai ușor de testat. (Testeci, nu-i așa?!) În loc să folosim new în funcția noastră pentru a instanția clasa bibliotecii GitHub, haideți să o transmitem ca parametru și să o instanțiem doar dacă trebuie.

 function github_issues_func( $atts, $gh=null ) { // Conditionally instantiate our class $gh = ( $gh ) ? $gh : new MyGithub(); …

Această modificare seamănă cu modelul de injectare a dependenței, ceea ce face funcția noastră mult mai ușor de testat. Testarea unitară WordPress depășește scopul acestui tutorial, dar este ușor să vedem cum această nouă versiune ne ajută să transmitem date API „false” funcției, astfel încât afirmațiile testului nostru să știe exact la ce să ne așteptăm.

Ceea ce am realizat până acum este bine și bun pentru un proiect intern care va fi folosit doar pe un singur depozit, dar ar fi mult mai util dacă utilizatorii ar putea configura din ce depozit să preia problemele. Să setăm asta.

În primul rând, vom folosi un cârlig WordPress pentru a înregistra noua noastră pagină de setări, iar funcția de apel invers va defini etichetele și titlurile meniului. Vom folosi aceeași abordare incrementală pentru ca acesta să funcționeze.

 // Register the menu. add_action( "admin_menu", "gh_plugin_menu_func" ); function gh_plugin_menu_func() { add_submenu_page( "options-general.php", // Which menu parent "GitHub", // Page title "GitHub", // Menu title "manage_options", // Minimum capability (manage_options is an easy way to target administrators) "github", // Menu slug "gh_plugin_options" // Callback that prints the markup ); } // Print the markup for the page function gh_plugin_options() { if ( !current_user_can( "manage_options" ) ) { wp_die( __( "You do not have sufficient permissions to access this page." ) ); } echo "Hello world!"; }

Acum ar trebui să vă puteți conecta la tabloul de bord și să vedeți noul meniu GitHub sub „Setări”, apoi faceți clic pe el pentru a vedea o pagină goală de setări cu „Bună lume!”

Pagina de pluginuri WordPress goală
Pagina de pluginuri WordPress goală. (Vezi versiunea mare)

În continuare, vom înlocui Hello word cu marcajul real al formularului. Îți voi da un exemplu barebones pe care îl poți coafa cât de puțin sau atât cât vrei.

 ?> <form method="post" action="<?php echo admin_url( 'admin-post.php'); ?>"> <input type="hidden" name="action" value="update_github_settings" /> <h3><?php _e("GitHub Repository Info", "github-api"); ?></h3> <p> <label><?php _e("GitHub Organization:", "github-api"); ?></label> <input class="" type="text" name="gh_org" value="<?php echo get_option('gh_org'); ?>" /> </p> <p> <label><?php _e("GitHub repository (slug):", "github-api"); ?></label> <input class="" type="text" name="gh_repo" value="<?php echo get_option('gh_repo'); ?>" /> </p> <input class="button button-primary" type="submit" value="<?php _e("Save", "github-api"); ?>" /> </form> <?php

Clasele CSS pe care le-am inclus se potrivesc cu cele utilizate de nucleul WordPress, ceea ce este o modalitate bună de a face ca pagina de opțiuni personalizate să arate decent, fără efort suplimentar.

Pagina personalizată cu setări WordPress cu stiluri de bază
Pagina personalizată cu setări WordPress cu stiluri de bază. (Vezi versiunea mare)

Există două lucruri importante de înțeles despre acest formular. În primul rând, punctul final la care se trimite trebuie să fie /wp-admin/admin-post.php . Puteți codifica această cale, dar dacă site-ul web este instalat într-un subdirector, nu va funcționa. Deci, folosim admin_url() încorporat pentru a-l crea dinamic.

În al doilea rând, observați intrarea ascunsă cu action nume . Acest câmp este modul în care WordPress știe ce să facă cu cererea de postare care este trimisă prin formular. value corespunde numelui cârligului de acțiune pe care îl vom folosi pentru a seta funcția de apel invers. Numele acțiunii la care ne vom conecta va fi această valoare, prefixată cu admin post . Deci, în cazul nostru, trebuie să adăugăm următoarele:

 add_action( 'admin_post_update_github_settings', 'github_handle_save' );

Mi se pare că acesta este unul dintre aspectele mai ciudate și mai puțin intuitive ale creării de meniuri de administrare personalizate, dar odată ce te obișnuiești cu el, este destul de nedureros. După cum probabil ați ghicit, al doilea parametru al add_action() este numele funcției noastre de apel invers care va salva de fapt valorile în baza de date.

 function github_handle_save() { // Get the options that were sent $org = (!empty($_POST["gh_org"])) ? $_POST["gh_org"] : NULL; $repo = (!empty($_POST["gh_repo"])) ? $_POST["gh_repo"] : NULL; // Validation would go here // Update the values update_option( "gh_repo", $repo, TRUE ); update_option("gh_org", $org, TRUE); // Redirect back to settings page // The ?page=github corresponds to the "slug" // set in the fourth parameter of add_submenu_page() above. $redirect_url = get_bloginfo("url") . "/wp-admin/options-general.php?page=github&status=success"; header("Location: ".$redirect_url); exit; }

Exemplul este, de asemenea, destul de minim. Într-un cadru de producție, probabil că ați dori să adăugați ceva validare. De asemenea, în acest exemplu, transmitem automat status=success la adresa URL. Markup-ul formularului nu îl folosește încă. Pentru a afișa condiționat un mesaj de succes, adăugați ceva de genul următor deasupra formularului în gh_plugin_options() :

 if ( isset($_GET['status']) && $_GET['status']=='success') { ?> <div class="updated notice is-dismissible"> <p><?php _e("Settings updated!", "github-api"); ?></p> <button type="button" class="notice-dismiss"> <span class="screen-reader-text"><?php _e("Dismiss this notice.", "github-api"); ?></span> </button> </div> <?php }

Dacă adăugați validare, utilizați același model pentru a transmite diferite stări și mesaje, astfel încât utilizatorul să știe dacă și de ce nu a reușit trimiterea formularului.

Acum ar trebui să puteți salva noile valori de proprietar și de depozit. Testați-l introducând proprietarul și depozitul oricărui proiect public pe GitHub. Pasul final este să reveniți la funcția de apelare shortcode github_issues_func() și să înlocuiți valorile codificate de proprietar și de depozit.

 … $issues = $gh->api("issue")->all(get_option("gh_org"), get_option("gh_repo")); …

Odată ce acesta este pus la punct, revedeți pagina în care ați adăugat codul scurt. Acum ar trebui să vedeți probleme de la orice proiect ați setat.

Runda bonus: Autentificare OAuth 2.0

Abordarea pe care am folosit-o mai sus funcționează excelent pentru depozitele publice, dar ce se întâmplă dacă dorim să folosim acest plugin cu un depozit privat care necesită autentificare? API-ul GitHub se autentifică folosind protocolul OAuth 2.0, care este ceea ce veți întâlni lucrând cu cele mai populare API-uri în aceste zile. Fluxul de lucru de bază OAuth 2.0 este următorul:

  1. Înregistrați o aplicație (uneori numită „client”) la furnizor și primiți un ID unic și cheie secretă.
  2. Aplicația dvs. face o solicitare către punctul final de autentificare al furnizorului, transmițând acreditările de mai sus, precum și o adresă URL de redirecționare pe care furnizorul o folosește pentru a redirecționa cererea înapoi către un punct final al aplicației dvs.
  3. Apoi utilizatorului i se solicită să accepte cererea dvs. de acces. Dacă o fac, furnizorul folosește adresa URL pe care ați trimis-o împreună cu solicitarea pentru a redirecționa utilizatorul înapoi la aplicația dvs., împreună cu un cod temporar.
  4. Aplicația dvs. captează acest cod și apoi face o a doua solicitare, trimițând acest cod înapoi furnizorului. Furnizorul răspunde cu un token de acces, pe care aplicația dvs. îl folosește apoi pentru a se autentifica la furnizor.

Vom începe prin a înregistra o aplicație cu GitHub. Ca și în cazul celor mai populare API-uri, această secțiune este situată în zona pentru dezvoltatori a site-ului web.

Noua pagină de înregistrare a aplicației GitHub
Noua pagină de înregistrare a aplicației GitHub. (Vezi versiunea mare)

Cel mai important lucru aici este adresa URL de apel invers de autorizare. Adresa URL de redirecționare transmisă la pasul trei trebuie să se potrivească cu ceea ce introduceți aici sau să o includă. Deci, în timpul dezvoltării, de obicei intru pe pagina de start a site-ului. În acest fel, aplicația mea poate redirecționa către orice cale.

Apoi, vom adăuga un al doilea formular pe pagina noastră de setări, în gh_plugin_options() , pentru a trimite ID-ul de client și secretul aplicației.

 <form method="post" action="<?php echo admin_url( 'admin-post.php'); ?>"> <input type="hidden" name="action" value="oauth_submit" /> <h3>Oauth 2.0</h3> <p> <label><?php _e("GitHub Application Client ID:", "github-api"); ?></label> <input class="" type="text" name="client_id" value="<?php echo get_option('client_id')?>" /> </p> <p> <label><?php _e("GitHub Application Client Secret:", "github-api"); ?></label> <input class="" type="password" name="client_secret" value="<?php echo get_option('client_secret')?>" /> </p> <input class="button button-primary" type="submit" value="<?php _e("Authorize", "github-api"); ?>" /> </form>

Pentru a face viața mai ușoară, voi folosi furnizorul GitHub pentru clientul OAuth 2.0 de la Liga Pachetelor Extraordinare. Deci, mai întâi, să folosim din nou Composer pentru a adăuga dependența:

 composer require league/oauth2-github

Rețineți că biblioteca GitHub de la KNP Labs are și suport OAuth 2.0 încorporat. Deci, în exemplul meu specific, acest lucru este oarecum redundant. Dar am vrut să introduc această bibliotecă deoarece aparține unei suită de biblioteci client OAuth 2.0 specifice furnizorului, care extind toate același cadru menținut de puternica League of Extraordinary Packages. Puteți vizualiza o listă completă a furnizorilor acceptați sau puteți citi instrucțiuni despre cum să extindeți cadrul pentru a sprijini un nou furnizor.

Să creăm o funcție pentru a solicita și a salva simbolul atunci când utilizatorul trimite formularul. Deoarece GitHub este unul dintre furnizorii deja acceptați, pot copia exemplul din documentația sa cu doar câteva modificări.

 function handle_oauth() { // If the form was just submitted, save the values // (Step 1 above) if ( isset($_POST["client_id"]) && isset($_POST["client_secret"]) ) { update_option( "client_id", $_POST["client_id"], TRUE ); update_option("client_secret", $_POST["client_secret"], TRUE); } // Get the saved application info $client_id = get_option("client_id"); $client_secret = get_option("client_secret"); if ($client_id && $client_secret) { $provider = new League\OAuth2\Client\Provider\Github([ "clientId" => $client_id, "clientSecret" => $client_secret, "redirectUri" => admin_url("options-general.php?page=github"), ]); } // If this is a form submission, start the workflow // (Step 2) if (!isset($_GET["code"]) && $_SERVER["REQUEST_METHOD"] === "POST") { // If we don't have an authorization code, then get one $authUrl = $provider->getAuthorizationUrl(); $_SESSION["oauth2state"] = $provider->getState(); header("Location: ".$authUrl); exit; // Check given state against previously stored one to mitigate CSRF attack // (Step 3 just happened and the user was redirected back) } elseif (empty($_GET["state"]) || ($_GET["state"] !== $_SESSION["oauth2state"])) { unset($_SESSION["oauth2state"]); exit("Invalid state"); } else { // Try to get an access token (using the authorization code grant) // (Step 4) $token = $provider->getAccessToken("authorization_code", [ "code" => $_GET["code"] ]); // Save the token for future use update_option( "github_token", $token->getToken(), TRUE ); } }

Și, la fel cum am făcut cu celălalt formular, trebuie să adăugăm cârligul de acțiune, astfel încât funcția să fie apelată atunci când formularul este salvat.

 add_action( "admin_post_oauth_submit", "handle_oauth" );

Salvarea formularului ar trebui să vă trimită acum la pagina de autorizare a furnizorului API. După autorizare, aplicația dvs. poate folosi simbolul salvat pentru a solicita date din depozitele private la care aveți acces. Biblioteca pe care o folosesc de KNP Labs are o metodă la îndemână pentru aceasta.

 $gh = new MyGithub(); $gh->authenticate( get_option("github_token"), NULL, Github\Client::AUTH_HTTP_TOKEN);

Bibliotecile vor diferi în ceea ce privește exact modul în care gestionează autentificarea, dar într-un fel sau altul, veți transmite tokenul, care va face apoi cereri autentificate în numele unui utilizator.

Concluzie

Am acoperit mult teren și am încercat să păstrez exemplele cât mai minim posibil, astfel încât fluxul de lucru general să rămână clar. Codul sursă complet din acest tutorial este disponibil. Sper că acum aveți o înțelegere clară a pieselor în mișcare implicate în crearea unui plugin WordPress care consumă API-uri de servicii terță parte și sperăm că sunteți inspirat să scrieți propriul plugin API WordPress.

Note finale

  • WordPress Codex (documentație)
  • API-ul GitHub (documentație)
  • OAuth 2.0 (documentație)
  • Compozitor (documentație)
  • Liga pachetelor extraordinare
  • Guzzle Documentație