Aggiornamento automatico di plugin WordPress da GitHub

| |

Attenzione

Articolo contenente diversi riferimenti tecnici che potrebbero non interessarti per nulla.
Se sei capitato qui leggendo abitualmente Gioxx’s Wall ma non possiedi alcuna installazione WordPress, probabilmente questo articolo non fa al caso tuo. Sentiti libero di scappare via velocissimo senza perderti con me in questo lungo corridoio buio 🥲

Ci sono mille buoni motivi per utilizzare GitHub e soci.
Uno tra questi è certamente il poter monitorare ogni singola modifica caricata, tornare agilmente indietro nel tempo, dormire sonni un po’ più tranquilli rispetto al tenere il file semplicemente salvato in una cartella del proprio disco (ed è già oro colato se quella cartella è sotto backup, oro che diventa ancora più prezioso se è pure sotto versioning, casi comunque assai rari nella normalità). Ho deciso di fare qualche ricerca in merito e sono arrivato a scoprire che sì, volendo si può pensare di tenere in piedi un plugin WordPress senza passare dal repository ufficiale e non rinunciando alla possibilità di farlo aggiornare automaticamente, proprio grazie a GitHub.

È su questo che voglio focalizzarmi oggi utilizzando questo articolo come appunti da recuperare facilmente in futuro (o che possano magari aiutare te che stai leggendo e vuoi fare la stessa cosa).

Come configurare gli aggiornamenti self-hosted per i tuoi plugin privati

Tutto è partito da questo articolo: rudrastyh.com/wordpress/self-hosted-plugin-update.html. È ben spiegato, il codice è ancora oggi attuale e facilmente adattabile e sì, funziona, testato con successo migrando un paio di plugin fondamentali di questo sito web, scritti ad-hoc per lui. Faccio un (non tanto) breve riepilogo di quanto messo in piedi.

  • Dovrai preparare (e poi tenere aggiornato nel corso del tempo) un file JSON contenente tutte le informazioni sul plugin.
  • Dovrai impacchettare il tuo plugin all’interno di un file ZIP assicurandoti che i file non si trovino nella root del file ZIP, bensì all’interno di una cartella, per capirci (i file del plugin si trovano all’interno della cartella wp-gwcustomboxes):

Aggiornamento automatico di plugin WordPress da GitHub

Io ho scelto di conservare sia il file JSON informativo che il codice del plugin (e i relativi rilasci sotto forma di pacchetto ZIP) su GitHub. L’articolo originale di Misha riporta invece una diversa fonte del file JSON rispetto a tutto il resto. La decisione è tua e non impatta in alcuna maniera il buon funzionamento del codice.

A proposito di file JSON, se ti stai chiedendo a cosa possa servire, è presto detto. Ti mostro quello che ho usato nel mio caso:

{
    "name" : "Custom Widgets per Gioxx's Wall",
    "slug" : "wp-gwcustomwidgets",
    "author" : "<a href='https://gioxx.org'>Gioxx</a>",
    "author_profile" : "https://profiles.wordpress.org/gioxx",
    "donate_link" : "https://ko-fi.com/gioxx",
    "version" : "0.21",
    "download_url" : "https://github.com/gioxx/wp-gwcustomwidgets/releases/download/0.21/wp-gwcustomwidgets.zip",
    "requires" : "6.2",
    "tested" : "6.2.1",
    "requires_php" : "8.0",
    "added" : "2015-08-21 00:00:00",
    "last_updated" : "2023-05-18 18:30:00",
    "homepage" : "https://gioxx.org",
    "sections" : {
    "description" : "Widget personalizzati che compaiono nella barra laterale di Gioxx's Wall: pillole, banco prova e molto altro ancora.",
    "installation" : "Un clic sul pulsante di attivazione e il gioco è fatto.",
    "changelog" : "<h4>18/5/23 (Preview4)</h4><ul><li>Change: dismetto widget Firefox-Addons.</li></ul><h4>18/5/23 (Preview3)</h4><ul><li>Bugfix: correggo warning PHP <em>Undefined array key \"title\"</em>.</li></ul><h4>18/5/23 (Preview2)</h4><ul><li>Bugfix: (urgente) modifico funzione del widget Firefox-Addons perché contiene una API Key privata (ora invalidata).</li></ul><h4>17/5/23 (Preview1)</h4><ul><li>Change: aggiornamenti automatici integrati con il rilascio via Github.</li><li>Change: elimino il file di changelog vecchio e migro tutto il contenuto in questo JSON informativo.</li><li>Improvement: aggiungo icona personalizzata per il plugin.</li><li>Improvement: pulizia e ottimizzazione codice.</li><li>Immagine di copertina di <a href=\"https://unsplash.com/@dancristianpaduret?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText\">Dan Cristian Pădureț</a> su <a href=\"https://unsplash.com/it/foto/noOXRT9gfQ8?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText\">Unsplash</a>.</li></ul><h3>Archivio</h3><h4>2021</h4><ul><li>5/1/21 Wdg-Covid19: ho modificato l'icona degli articoli Covid-19.</li><li>24/1/21 Wdg-Covid19: ho incluso la possibilità di specificare quanti articoli caricare nel widget, fino a un massimo di 10.</li></ul><h4>2020</h4><ul><li>Wdg-BancoProva: propongo i link alle prove precedenti e agli ultimi acquisti fatti.</li><li>Wdg-Donazioni: standardizzo il widget in base agli altri creati per la sidebar di Gioxx.org</li><li>Wdg-BancoProva: metto a posto i link alle ultime banco prova / banco prova lampo (separandoli). Tolgo di mezzo tutto quanto, lascio solo il blocco relativo al Banco Prova e creo widget separati per le altre aree coperte.</li><li>Wdg-Evidenza: nuove modifiche CSS.</li><li>Wdg-Eventi: nuove modifiche CSS.</li><li>Wdg-Donazioni: nuove modifiche CSS.</li><li>Wdg-BancoProvaConsole: nuove modifiche CSS e nuovo metodo per integrare le news da gaming.gioxx.org (via rss2json).</li><li>Wdg-BancoProva: nuove modifiche CSS e imposto a 3 i banco prova / banco prova lampo nell'elenco puntato.</li><li>Wdg-Covid19: per riutilizzare il tag Covid-19 modifico la ricerca per mettere nella Sidebar solo gli articoli con Custom field \"covid19\" con valore \"sidebar\".</li><li>Wdg-Evidenza: modifico icona in evidenza.</li><li>Wdg-BancoProvaConsole: modifico puntamento RSS feed per cattura via rss2json.</li><li>Wdg-BancoProvaConsole: se il json delle notizie da Tumblr è vuoto, allora faccio sparire anche la dicitura che carico notizie dalla fonte esterna (modifica meramente estetica).</li><li>Wdg-FxAddons: nuovo widget che mi è utile richiamare tra le FAQ per la pagina Firefox Addons. Ha una porzione CSS dedicata per l'elenco delle notizie catturate in JSON dal feed privato di AMO.</li><li>Wdg-Evidenza: cambio icona In Evidenza e cambio anche lo stile dell'header del box.</li><li>Wdg-Eventi: cambio icona Eventi e cambio anche lo stile dell'header del box.</li><li>Wdg-Donazioni: cambio lo stile dell'header del box.</li><li>Wdg-BancoProvaConsole: cambio lo stile dell'header del box.</li><li>Wdg-BancoProva: cambio lo stile dell'header del box.</li></ul><h4>2019</h4><ul><li>Wdg-Donazioni: aggiungo collegamento a donazione con Satispay.</li><li>Wdg-RicercaGoogle (Deprecated): fix estetico.</li><li>Wdg-Facebook (Deprecated): fix estetico.</li><li>Wdg-Donazioni: fix estetico.</li><li>Wdg-BancoProva: fix estetico.</li><li>Wdg-BancoProva: sposto box \"in evidenza console\" sotto gli altri articoli in primo piano.</li><li>Wdg-Donazioni: metto a posto referral Amazon.</li></ul><h4>2018</h4><ul><li>Wdg-Donazioni: inserisco Patreon e BuyMeACoffee, sostituisco icone con fontawesome.</li><li>Wdg-Donazioni: messo a posto dettaglio estetico.</li><li>Wdg-Donazioni: corretto Buy Me A Coffee.</li><li>Wdg-Donazioni: aggiunto collegamento Amazon tra le possibili donazioni.</li><li>Wdg-RicercaGoogle (Deprecated): trasformazione in widget. Inserito ordine widget. Reintegro lista modifiche.</li><li>Wdg-Facebook (Deprecated): trasformazione in widget. Inserito ordine widget. Reintegro lista modifiche.</li><li>Wdg-Facebook (Deprecated): nascondo banner (fco + ShortPixel).</li><li>Wdg-Donazioni: trasformazione in widget. Inserito ordine widget. Reintegro lista modifiche.</li><li>Wdg-BancoProva: trasformazione in widget. Inserito ordine widget. Reintegro lista modifiche.</li><li>Wdg-Donazioni: piccolo dettaglio estetico (spaziatura tra elenco e testo prima).</li><li>Wdg-BancoProva: il box dedicato all'ultimo gioco recensito (ordine Wdg-BancoProva: copertina, titolo, estratto).</li></ul><h4>2017</h4><ul><li>Wdg-RicercaGoogle (Deprecated): puntamenti in HTTPS.</li><li>Wdg-Facebook (Deprecated): puntamenti in HTTPS.</li><li>Wdg-Donazioni: puntamenti in HTTPS.</li><li>Wdg-BancoProva: puntamenti in HTTPS.</li><li>Wdg-Donazioni: modifico il box per sostenere il blog.</li><li>Wdg-RicercaGoogle (Deprecated): modificata la ricerca, utilizza ora Google Custom Search.</li><li>Wdg-Facebook (Deprecated): ho commentato il \"Grazie a\" prima dei blocchi partner (immagini, sotto badge Facebook).</li></ul><h4>2016</h4><ul><li>Wdg-Facebook (Deprecated): aggiunto box like pagina Gioxx's Wall su Facebook</li><li>Wdg-Facebook (Deprecated): sostituzione blocco Fuorigio.co con box sponsorizzazioni</li><li>Wdg-Facebook (Deprecated): \"aggiustato\" box Facebook rotto (FbMerda v.0.1)</li></ul><h4>2015</h4><ul><li>Wdg-RicercaGoogle (Deprecated): integrato modulo di ricerca in cima alla Sidebar, puliti DIV inutili nei box custom.</li><li>Wdg-Donazioni: messo a posto collegamento PayPal.me</li><li>Wdg-Donazioni: modifica blocco donazioni, integrazione abbonamento PayPal</li><li>Wdg-Donazioni: aggiunta icona handshake per blocco donazioni</li></ul>"
    },
    "banners" : {
        "low" : "https://gioxx.github.io/wp-gwcustomwidgets/img/banner-772x250.jpg",
        "high" : "https://gioxx.github.io/wp-gwcustomwidgets/img/banner-1544x500.jpg"
    }
}

Al suo interno – come potrai notare tu stesso – sono conservate informazioni che riguardano il plugin, la sua descrizione, le varie modifiche rilasciate nel tempo, la versione, ecc.
Se vuoi dare un’occhiata a un file un po più snello puoi puntare il browser a quello che Misha ha pubblicato come esempio: rudrastyh.com/wp-content/uploads/updater/info.json.

Ciò che manca all’appello ora è tutto il blocco di codice che dovrà occuparsi del controllo di disponibilità degli aggiornamenti in base a quanto riportato nel file JSON. Si tratta nello specifico di quello che puoi vedere tu stesso all’indirizzo go.gioxx.org/te9lf:

if ( !class_exists('gwplgUpdateChecker_wdg') ) {
    class gwplgUpdateChecker_wdg{
        public $plugin_slug;
        public $version;
        public $cache_key;
        public $cache_allowed;

        public function __construct() {
            $this->plugin_slug = plugin_basename( __DIR__ );
            $this->version = '0.21';
            $this->cache_key = 'customwidgets_updater';
            $this->cache_allowed = true;

            add_filter( 'plugins_api', array( $this, 'info' ), 20, 3 );
            add_filter( 'site_transient_update_plugins', array( $this, 'update' ) );
            add_action( 'upgrader_process_complete', array( $this, 'purge' ), 10, 2 );
        }

        public function request() {
            $remote = get_transient( $this->cache_key );
            if( false === $remote || ! $this->cache_allowed ) {
                $remote = wp_remote_get(
                    'https://gioxx.github.io/wp-gwcustomwidgets/plg-customwidgets.json',
                    array(
                        'timeout' => 10,
                        'headers' => array(
                            'Accept' => 'application/json'
                        )
                    )
                );

                if(
                    is_wp_error( $remote )
                    || 200 !== wp_remote_retrieve_response_code( $remote )
                    || empty( wp_remote_retrieve_body( $remote ) )
                ) {
                    return false;
                }

                set_transient( $this->cache_key, $remote, DAY_IN_SECONDS );

            }
            $remote = json_decode( wp_remote_retrieve_body( $remote ) );
            return $remote;
        }


        function info( $res, $action, $args ) {
            // do nothing if you're not getting plugin information right now
            if( 'plugin_information' !== $action ) {
                return $res;
            }

            // do nothing if it is not our plugin
            if( $this->plugin_slug !== $args->slug ) {
                return $res;
            }

            // get updates
            $remote = $this->request();

            if( ! $remote ) {
                return $res;
            }

            $res = new stdClass();
            $res->name = $remote->name;
            $res->slug = $remote->slug;
            $res->version = $remote->version;
            $res->tested = $remote->tested;
            $res->requires = $remote->requires;
            $res->author = $remote->author;
            $res->author_profile = $remote->author_profile;
            $res->download_link = $remote->download_url;
            $res->trunk = $remote->download_url;
            $res->requires_php = $remote->requires_php;
            $res->last_updated = $remote->last_updated;
            $res->sections = array(
                'description' => $remote->sections->description,
                'installation' => $remote->sections->installation,
                'changelog' => $remote->sections->changelog
            );

            if( ! empty( $remote->banners ) ) {
                $res->banners = array(
                    'low' => $remote->banners->low,
                    'high' => $remote->banners->high
                );
            }

            return $res;
        }

        public function update( $transient ) {
            if ( empty($transient->checked ) ) {
                return $transient;
            }
            $remote = $this->request();

            if(
                $remote
                && version_compare( $this->version, $remote->version, '<' )
                && version_compare( $remote->requires, get_bloginfo( 'version' ), '<=' )
                && version_compare( $remote->requires_php, PHP_VERSION, '<' )
            ) {
                $res = new stdClass();
                $res->slug = $this->plugin_slug;
                $res->plugin = plugin_basename( __FILE__ ); // example: misha-update-plugin/misha-update-plugin.php
                $res->new_version = $remote->version;
                $res->tested = $remote->tested;
                $res->package = $remote->download_url;

                $transient->response[ $res->plugin ] = $res;
        	}
            return $transient;
        }

        public function purge( $upgrader, $options ) {
            if (
                $this->cache_allowed
                && 'update' === $options['action']
                && 'plugin' === $options[ 'type' ]
            ) {
                // just clean the cache when new plugin version is installed
                delete_transient( $this->cache_key );
            }
        }

    }
    new gwplgUpdateChecker_wdg();
}

add_filter( 'plugin_row_meta', function( $links_array, $plugin_file_name, $plugin_data, $status ) {
    if( strpos( $plugin_file_name, basename( __FILE__ ) ) ) {
        $links_array[] = sprintf(
            '<a href="%s" class="thickbox open-plugin-details-modal">%s</a>',
            add_query_arg(
                array(
                    'tab' => 'plugin-information',
                    'plugin' => plugin_basename( __DIR__ ),
                    'TB_iframe' => true,
                    'width' => 772,
                    'height' => 788
                ),
                admin_url( 'plugin-install.php' )
            ),
            __( 'View details' )
        );
    }
    return $links_array;
}, 25, 4 );

Se vuoi dare un’occhiata al codice originale di Misha, puoi puntare il browser all’indirizzo github.com/rudrastyh/misha-update-checker/blob/main/misha-update-checker.php.

Il primo migrato: Disqus, Recent Comments per WordPress

Vecchio, ma ancora funzionante, Disqus: Recent Comments è stato migrato portato su GitHub (github.com/gioxx/disqus-recent-comments) ed è stato aggiornato integrando il codice che gli permetterà di continuare a cercare e installare futuri (eventuali) aggiornamenti presi direttamente dalla piattaforma di Microsoft. Testato su WordPress 6.0.2 con successo ma – come forse già sai – qualche tempo fa ho deciso di abbandonare definitivamente Disqus e riportare in locale i commenti degli articoli (vedi: Why I Deleted Disqus and Why You Should Too).

Questo riportato sopra è solo un metodo possibile per gestire gli aggiornamenti dei plugin tramite GitHub. Esistono alcune alternative gratuite e non, alcune particolarmente interessanti, che fanno da tramite e permettono di tenere aggiornati plugin pubblicati su GitHub anche se privi di codice adatto alla ricerca dell’aggiornamento (e relativa installazione). Diciamo che l’argomento sta interessandomi ultimamente, potrebbero seguire nuove puntate in merito (anche se so già che ti annoierò da morire!).

L’articolo termina qui, spero davvero di non averti ammorbato più del dovuto. Se hai dubbi in merito sfrutta pure l’area commenti, proverò a esserti d’aiuto.

#KeepItSimple


Immagine di copertina: Roman Synkevych on Unsplash
Riconoscimenti:
rudrastyh.com/wordpress/self-hosted-plugin-update.html
github.com/rudrastyh/misha-update-checker
anchor.host/using-github-to-self-host-updates-for-wordpress-plugins
github.com/WPFreighter/wp-freighter/blob/master/app/Updater.php
wpfreighter.com/plugin-wpfreighter.json
github.com/rudrastyh/misha-update-checker/issues/11

Correzioni, suggerimenti? Lascia un commento nell'apposita area qui di seguito o contattami privatamente.
Ti è piaciuto l'articolo? Offrimi un caffè! ☕ :-)

L'articolo potrebbe non essere aggiornato

Questo post è stato scritto più di 5 mesi fa, potrebbe non essere aggiornato. Per qualsiasi dubbio ti invito a lasciare un commento per chiedere ulteriori informazioni! :-)

Condividi l'articolo con i tuoi contatti:
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Commenti
Inline Feedbacks
View all comments