Scrivere migliori API e librerie per WordPress

Sembra che tutto ciò che tocchiamo sia progettato con cura: siti web, telefoni, mappe della metropolitana e così via. Anche le cose che davamo per scontate: termostati, rilevatori di fumo e cruscotti auto ora ricevono un'attenta terapia utente.

Il design non riguarda solo l'aspetto grafico: si tratta di considerare ogni modo in cui un utente deve interagire con il nostro dispositivo / strumento / schermo / oggetto. 

Questo vale anche per la programmazione.

(Un) programmazione progettata

I linguaggi di programmazione sono mondi grandi e complicati. Persino il PHP, che molti snobi della programmazione pensano sia troppo "facile", è in realtà un mix piuttosto complicato di funzioni e classi che si comportano in modi molto incoerenti. 

La sintassi, i metodi e la denominazione si sono evoluti nel corso degli anni su milioni di utenti e applicazioni diversi. La maggior parte tende a riflettere la costruzione sottostante degli interni - non necessariamente come vorresti usarla.

Grandi momenti nel design delle API: jQuery

Quando ho iniziato a scrivere JavaScript nel 2006 o giù di lì, era un casino. Ecco come troverei un tag con una certa classe e poi lo sposterei attorno al DOM:

var uls = getElementsByTagName ("ul"); var classToSearch = "cibi"; per (var i = 0; i < uls.length; i++)  var classes = uls[i].getClasses(); for (var j = 0; j < classes.length; j++) if (classes[j] == classToSearch) myUL = uls[i];    var $li = document.createElement('li'); $li.innerHTML = 'Steak'; myUL.innerHTML += $li;

Fatto!

jQuery ha reso nuovamente divertente JavaScript. Verso la fine degli anni 2000, l'effetto è stato così drammatico che ricordo che mio padre mi ha chiesto di "qualche cosa da jkwery" di cui ha letto nel Wall Street Journal. Ma nonostante il suo grande effetto, jQuery non ha aggiunto alcuna "nuova funzionalità" a JavaScript. Ci sono volute solo le cose che gli sviluppatori dovevano fare e l'hanno abbattuto in schemi davvero chiari.

Piuttosto che re-inventare come trovare elementi sulla pagina, hanno sfruttato ciò che la gente già sapeva: i selettori CSS. Quindi si trattava solo di raccogliere molte azioni comuni e organizzarle in poche decine di funzioni. Proviamo di nuovo l'esempio precedente, ora con jQuery:

var $ li = $ ('
  • Bistecca
  • '); $ ( "Ul.foods") aggiungere ($ li).;

    Nel 2006, ho comprato un libro di 680 pagine su Ajax. Con la grande API di jQuery, questo è stato praticamente sostituito da questo:

    $ .Post ();

    L'API di WordPress

    Anche se API è arrivata a significare "servizio di terze parti" significa semplicemente l'interfaccia di programmazione per parlare con un sistema. Proprio come c'è un'API di Twitter o un'API di Facebook c'è un'API di WordPress. Non si eseguono query di database non elaborate per creare un post, giusto? Usate wp_insert_post.

    Ma molti fori di progettazione affliggono l'API di WordPress. Potresti usare get_the_title ma get_the_permalink genera un errore, tu usi get_permalink. Ehi, quando hai un progetto open source pluridecennale che coinvolge il codice di migliaia di persone e milioni di utenti: otterrai qualche stranezza.

    Puoi risparmiare un sacco di tempo mascherando queste stranezze e scrivendo alle abitudini e ai comportamenti del programmatore per cui stai scrivendo (che potrebbe essere tu). È qui che puoi progettare l'interfaccia giusta per programmare plug-in e temi che fai ogni giorno.


    La soluzione

    Per velocizzare il lavoro e ridurre le attività ripetitive, ho creato librerie per gestire i comandi e le personalizzazioni di cui ho bisogno tutto il tempo.

    1. Scorciatoie per attività comuni

    Prendi, per esempio, afferrando la fonte della miniatura di un post. Si scopre che non esiste una funzione WordPress integrata per catturare una miniatura basata sull'ID di un post (solo il attaccamento ID). 

    Il che significa che spesso mi trovo a fare questo:

    $ thumb_id = get_post_thumbnail_id (get_the_ID ()); $ src = wp_get_attachment_thumb_url ($ thumb_id); eco '';

    Ma dev'essere un modo migliore!

    function get_thumbnail_src ($ post) $ thumb_id = get_post_thumbnail_id ($ post); $ src = wp_get_attachment_thumb_url ($ thumb_id); restituisce $ src;  eco '';

    2: Ingressi non prevedibili, uscita prevedibile

    Molto meglio! In effetti ti ritrovi a utilizzarlo tutto il tempo e poi a condividere con altri sviluppatori della tua azienda. 

    Il tuo amico ha problemi con esso, quindi ti chiama per eseguire il debug e vedi:

    eco '';

    Quindi sembra che abbia usato accidentalmente get_post invece di get_the_ID. Lo stai urlando. Ma aspetta un secondo, perchè no renderlo più accettabile? 

    Forse possiamo adattare la nostra funzione in modo che possa prendere un WP_Post oggetto e ancora dare all'utente ciò che si aspettano. Torniamo a quella funzione:

    function get_thumbnail_src ($ post) if (is_object ($ post) && isset ($ post-> ID)) $ post = $ post-> ID;  else if (is_array ($ post) && isset ($ post ['ID'])) $ post = $ post ['ID'];  $ thumb_id = get_post_thumbnail_id ($ post); $ src = wp_get_attachment_thumb_url ($ thumb_id); restituisce $ src; 

    Quindi se mandano un WP_Post oggetto o un array, la tua funzione li aiuterà comunque a ottenere ciò di cui hanno bisogno. Questa è una parte enorme di un'API di successo: nascondere le budella disordinate. Potresti creare funzioni separate per get_thumbnail_src_by_post_id e get_thumbnail_src_by_wp_post_object. 

    In effetti, per trasformazioni più complesse potrebbe essere preferibile, ma è possibile semplificare l'interfaccia disponendo di una singola funzione per la subroutine corretta. Indipendentemente da ciò che l'utente invia, la funzione restituisce costantemente una stringa per l'origine dell'immagine. 

    Andiamo avanti: cosa succede se mandano Niente?

    3. Impostazioni predefinite sensibili

    function get_thumbnail_src ($ post = false) if (false === $ post) $ post = get_the_ID ();  else if (is_object ($ post) && isset ($ post-> ID)) $ post = $ post-> ID;  else if (is_array ($ post) && isset ($ post ['ID'])) $ post = $ post ['ID'];  $ thumb_id = get_post_thumbnail_id ($ post); $ src = wp_get_attachment_thumb_url ($ thumb_id); restituisce $ src; 

    Abbiamo semplificato ancora una volta in modo che l'utente non debba inviare un post o anche un ID post. Quando sei nel ciclo, tutto ciò che serve è:

    eco '';

    La nostra funzione imposterà automaticamente l'ID del post corrente. Questo si sta trasformando in una funzione davvero preziosa. Per assicurarci che funzioni correttamente, racchiudiamolo all'interno di una classe in modo da non inquinare lo spazio dei nomi globale.

    / * Nome plugin: JaredTools Descrizione: My toolbox per temi WordPress. Autore: Jared Novack Versione: 0.1 Autore URI: http://upstatement.com/ * / class JaredsTools funzione statica pubblica get_thumbnail_src ($ post = false) if (false === $ post) $ post = get_the_ID () ;  else if (is_object ($ post) && isset ($ post-> ID)) $ post = $ post-> ID;  else if (is_array ($ post) && isset ($ post ['ID'])) $ post = $ post ['ID'];  $ thumb_id = get_post_thumbnail_id ($ post); $ src = wp_get_attachment_thumb_url ($ thumb_id); restituisce $ src; 

    E per favore non prefisso la tua classe con WP. Sto rendendo questa una funzione statica pubblica perché la voglio accessibile ovunque, e non cambia: l'input o l'esecuzione non cambia la funzione o l'oggetto. 

    L'ultima chiamata a questa funzione è:

    eco '';

    Design First, Build Later

    Passiamo ad un bisogno più complicato. Quando scrivo plugin, trovo che devo sempre generare diversi tipi di errori e / o messaggi di aggiornamento. 

    Ma la sintassi basata sugli eventi mi ha sempre infastidito:

    add_action ('admin_notices', 'show_my_notice'); functon show_my_notice () echo '

    La tua cosa è stata aggiornata

    ';

    Ci sono molte buone ragioni per cui WordPress segue questa architettura basata sugli eventi. Ma non è intuitivo, a meno che tu non voglia sederti intorno e memorizzare diversi filtri e azioni. 

    Facciamo in modo che questo match sia il caso d'uso più semplice: ho bisogno di mostrare un avviso di amministrazione. Mi piace progettare questa API-first: dove trovo il modo migliore per fare riferimento alla funzione nel mio codice. Mi piacerebbe leggere così:

    function thing_that_happens_in_my_plugin ($ post_id, $ valore) $ updated = update_post_meta ($ post_id, $ valore); if ($ updated) JaredsTools :: show_admin_notice ("La tua cosa è stata aggiornata") else JaredsTools :: show_admin_notice ("Errore durante l'aggiornamento delle tue cose", "errore"); 

    Una volta che ho progettato l'end-point, posso soddisfare i requisiti di progettazione:

    class JaredsTools public static function show_admin_notice ($ message, $ class = 'updated') add_action ('admin_notices', function () use ($ message, $ class) echo '

    '$ Messaggio.'

    '; );

    Molto meglio! Ora non ho bisogno di creare tutte queste funzioni extra o ricordare nomi pazzeschi. Qui sto usando le funzioni anonime PHP (chiamate anche "chiusure") che ci permettono di legare una funzione direttamente a un'azione o un filtro. 

    Ciò ti evita di avere un sacco di funzioni extra che galleggiano attorno ai tuoi file. Il uso comando ci permette di passare argomenti dalla funzione genitore alla chiusura del bambino.

    Sii intuitivo

    Ora un altro collega ti chiama. Lei non sa perché il suo avviso di amministratore non sta diventando rosso:

    JaredsTools :: show_admin_notice ("Errore durante l'aggiornamento delle cose", "rosso");

    È perché sta inviando "rosso" (che si aspetterebbe avrebbe trasformato la scatola rossa) quando in realtà avrebbe dovuto inviare il nome del classe quello trigger rosso. Ma perché non renderlo più facile?

    funzione statica pubblica show_notice ($ message, $ class = 'updated') $ class = trim (strtolower ($ class)); if ('yellow' == $ class) $ class = 'updated';  if ('red' == $ class) $ class = 'error';  add_action ('admin_notices', function () use ($ text, $ class) echo '

    '. $ testo. '

    '; );

    Ora abbiamo accettato una maggiore tolleranza dell'utente che renderà più semplice la condivisione e per noi quando torneremo a utilizzarla da mesi.


    Conclusione

    Dopo aver creato alcuni di questi, ecco alcuni dei principi che ho imparato a renderli davvero utili per la mia squadra e per me.

    1. Disegna prima e lascia che la build della funzione corrisponda a come le persone vogliono usarla.
    2. Salva la tua tastiera! Crea scorciatoie per le attività più comuni.
    3. Fornire valori predefiniti sensibili.
    4. Sii minimo. Lascia che la tua biblioteca gestisca l'elaborazione.
    5. Essere indulgenti su input, ma precisi sull'output.
    6. Detto questo, usa il minor numero possibile di argomenti di funzione, quattro è un buon massimo. Dopo ciò, dovresti renderlo un array di opzioni.
    7. Organizza la tua biblioteca in classi separate per coprire diverse aree (admin, immagini, post personalizzati, ecc.).
    8. Documento con codice di esempio.

    A Upstatement, le nostre librerie per Timber semplificano la creazione di temi e Jigsaw fornisce scorciatoie per risparmiare tempo per personalizzare ogni installazione.

    Il risparmio di tempo che questi strumenti offrono ci consente di dedicare più tempo a costruire le parti nuove e innovative di ogni sito o app. Prendendo i comandi che sono altrimenti esoterici (come l'aggiunta di una colonna alle tabelle dei post di amministrazione) e rendendo semplici interfacce: qualsiasi progettista o sviluppatore della nostra azienda può personalizzare completamente ciascun sito con la stessa potenza di uno sviluppatore professionista di WordPress.