Qual è la tua migliore pratica per eseguire script una tantum?

29 gen 2014, 18:24:47
Visualizzazioni: 21.4K
Voti: 42

Il Problema

Ci siamo tutti trovati in una situazione del genere, e molte domande su questo sito necessitano di una soluzione simile. Devi aggiornare un database, inserire molti dati automaticamente, convertire meta_keys, o qualcosa di simile.

Naturalmente, in un sistema funzionante basato sulle migliori pratiche questo non dovrebbe accadere.

Ma poiché accade, mi piacerebbe conoscere la tua soluzione personale a questo problema e perché hai scelto la tua.

La Domanda

Come implementi gli script una tantum nella tua installazione WordPress (in esecuzione)?

Il problema qui è principalmente dovuto alle seguenti ragioni:

  • Gli script che inseriscono dati non dovrebbero essere eseguiti più di una volta
  • Gli script che richiedono molte risorse non dovrebbero essere eseguiti in un momento in cui non possono essere monitorati
  • Non dovrebbero essere eseguiti per errore

Il Motivo per cui chiedo

Ho la mia pratica personale, la posterò nelle risposte. Poiché non so se sia la migliore soluzione disponibile, vorrei conoscere la vostra. Inoltre, questa è una domanda che viene posta molte volte nel contesto di altre domande, e sarebbe fantastico avere una risorsa che raccolga le idee.

non vedo l'ora di imparare da voi :)

8
Commenti

Se è davvero una cosa che si fa una sola volta, allora scrivo lo script, lo eseguo e poi lo cancello. Nessuno potrà più eseguirlo dopo. Come tutte le cose, il codice è effimero. ;)

Otto Otto
29 gen 2014 20:44:20

Il fatto è che sono preoccupato che uno script possa essere chiamato una seconda volta, per coincidenza. Ma ho usato il tuo approccio innumerevoli volte ;)

fischi fischi
29 gen 2014 22:31:21

Eseguilo su una pagina di amministrazione di un plugin, per me ha sempre funzionato. Puoi aggiungere controlli di autorizzazione all'inizio della pagina per assicurarti che sia tu, se necessario.

Andrew Bartel Andrew Bartel
29 gen 2014 23:14:15

ma non stai parlando di esecuzione programmata una tantum, solo di quella manuale?

birgire birgire
3 feb 2014 13:08:42

Sì, sto parlando solo di operazioni manuali una tantum, come script di migrazione ecc., non di eventi programmati con wp-cron.

fischi fischi
3 feb 2014 14:10:32

Credo di non capire perché vorresti fare questo, se vuoi cambiare il nome di un meta_key usato sia nel database che nel tuo codice, esiste davvero uno script che fa tutto in una sola esecuzione? Anche se non dovessi modificare il database e avessi solo bisogno di cambiare il codice, se includessi uno script via include non rimarrebbe statico finché la pagina non viene chiamata? Suppongo di non aver capito il punto :/

Howdy_McGee Howdy_McGee
5 feb 2014 23:00:55

Il punto è, ad esempio, convertire le informazioni SEO da un plugin a un altro, senza perdere dati, o inserire una grande quantità di contenuti - operazione che deve essere eseguita una sola volta. E con le funzioni integrate di WordPress sei molto più veloce e sicuro rispetto all'esecuzione di query direttamente nel database.

fischi fischi
6 feb 2014 09:11:51

Non era il mio obiettivo fare questo - ma dopo il voto sceglierò la mia risposta, basandomi esclusivamente sui risultati.

fischi fischi
11 feb 2014 08:22:55
Mostra i restanti 3 commenti
Tutte le risposte alla domanda 12
1
26

Personalmente utilizzo una combinazione di:

  • un file dedicato allo script one-time
  • un transient per impedire l'esecuzione accidentale dello script più di una volta
  • gestione delle capacità o controllo utente per assicurarmi che lo script venga eseguito solo da me.

Struttura

Utilizzo un file (onetime.php) nella mia cartella inc, che viene incluso nel functions.php e poi eliminato dopo l'uso.

include( 'inc/onetime.php' );

Il file per lo script stesso

Nel mio onetime.php inserisco la mia funzione f711_my_onetime_function(). Potrebbe essere qualsiasi funzione. Suppongo che il tuo script sia già testato e funzioni correttamente.

Per controllare l'esecuzione dello script, utilizzo entrambi:

Controllo delle capacità

Per impedire ad altri utenti di eseguire accidentalmente il mio script:

if ( current_user_can( 'manage_options' ) ) // verifica i permessi di amministratore

oppure

if ( get_current_user_id() == 711 ) // verifica se sono io - preferisco limitare l'esecuzione solo a me, non a tutti gli amministratori.

Un transient

per impedire a me stesso di eseguire accidentalmente lo script più di una volta.

$transient = 'f711_my_onetime_check';
if ( !get_transient( $transient ) ) // verifica se la funzione non è stata già eseguita.

Il file per l'esecuzione dello script nella mia funzione f711_my_onetime_function() sarebbe così:

$transient = 'f711_my_onetime_check';
if ( get_current_user_id() == 711 && !get_transient( $transient ) ) {

    set_transient( $transient, 'locked', 600 ); // blocca la funzione per 10 minuti
    add_action( 'wp_footer', 'f711_my_onetime_function' ); // esegue la mia funzione sull'hook desiderato.

}

function f711_my_onetime_function() {
    // tutta la mia gloriosa magia one-time.
}

Il motivo per cui imposto il transient immediatamente dopo aver verificato la sua esistenza è che voglio che la funzione venga eseguita dopo che lo script è stato bloccato per evitare esecuzioni multiple.

Se ho bisogno di un output dalla mia funzione, lo stampo come commento nel footer o a volte applico un filtro al contenuto.

Il tempo di blocco è impostato a 10 minuti, ma può essere modificato in base alle tue esigenze.

Pulizia

Dopo l'esecuzione corretta del mio script, elimino l'include dal functions.php e rimuovo il file onetime.php dal server. Poiché ho utilizzato un timeout per il transient, non è necessario ripulire il database, ma ovviamente potresti anche eliminare il transient dopo aver rimosso il file.

29 gen 2014 18:24:47
Commenti

Ho pensato di aggiungere la mia risposta a questa, ma dopo aver letto il tuo elenco proprio in cima a questa risposta... non lo farò più poiché il mio approccio sembra quasi identico. Quindi +1 per questo - anche per i pensieri dettagliati su questo argomento.

tfrommen tfrommen
5 feb 2014 22:58:38
2
20

Puoi anche fare così:

esegui onetime.php e rinominalo dopo l'esecuzione.

if ( current_user_can( 'manage_options' ) ) {

    if( ! file_exists( '/percorso/di/onetime.php' ) )
      return;
    add_action( 'wp_footer', 'ravs_my_onetime_function' ); // esegue la mia funzione sull'hook desiderato.

}

function ravs_my_onetime_function() {

    // tutta la mia gloriosa magia one-time.
    include( '/percorso/di/onetime.php' );

   // dopo tutta l'esecuzione rinomina il tuo file;
   rename( '/percorso/di/onetime.php', '/percorso/di/onetime-backup.php');
}
5 feb 2014 21:58:56
Commenti

Questo è ciò che facciamo; è praticamente garantito essere a prova di errore.

Qix - MONICA WAS MISTREATED Qix - MONICA WAS MISTREATED
6 gen 2015 23:07:52

Perfetto, non so perché questa idea non mi sia venuta in mente, grazie :)

Shahin Shahin
11 feb 2020 09:01:46
1

Ho creato uno script Phing da riga di comando per questo, non è niente di speciale se non il caricamento di uno script esterno da eseguire. Il motivo per cui l'ho utilizzato tramite CLI è perché:

  • Non voglio che venga caricato per errore (bisogna digitare un comando)
  • È sicuro poiché può essere eseguito al di fuori della root web, in altre parole può influenzare WP ma WP non può raggiungere lo script in alcun modo.
  • Non aggiunge alcun codice a WP o al database stesso.

require('..percorso a ../wp-blog-header.php');
//vari globali di WP
define('WP_USE_THEMES', false);
//codice personalizzato

Quindi puoi usare Phing, o la CLI PHP e dormire sonni tranquilli. WP-CLI è anche una buona alternativa anche se non ricordo se si possa usare al di fuori della root web.

Dato che questo è un post popolare, ecco un esempio dello script: https://github.com/wycks/WordPhing (run.php)

6 feb 2014 04:54:58
Commenti

Sembra bello e semplice, oltre che sicuro. Hai anche affrontato una delle mie principali preoccupazioni (eseguire accidentalmente due volte il comando) in modo abbastanza esteso utilizzando la riga di comando. Bella idea!

fischi fischi
6 feb 2014 09:18:15
0

In condizioni ideali accederei al server via SSH ed eseguirei la funzione manualmente utilizzando wp-cli.

Spesso però questo non è possibile, quindi tendo a impostare una variabile $_GET e ad agganciarla a 'init', ad esempio:

add_action( 'init', function() {
    if( isset( $_GET['one_time'] ) && $_GET['one_time'] == 'an_unlikely_string' ) {
        do_the_one_time_thing();
    }
});

per poi visitare

http://my_blog.com/?one_time=an_unlikely_string

e disabilitare l'hook una volta completata l'operazione.

5 feb 2014 21:38:38
0

Un altro modo piuttosto semplice per eseguire uno script una tantum è farlo utilizzando un plugin MU.

Inserisci il codice in un file PHP (ad esempio, one-time.php) che carichi nella cartella dei plugin MU (di default /wp-content/mu-plugins), modifica i permessi del file, esegui il plugin (cioè, in base all'hook scelto, fondamentalmente devi solo visitare il frontend/backend), e il gioco è fatto.

Ecco uno scheletro di base:

/**
* Classe principale (e unica).
*/
class OneTimeScript {

    /**
     * Hook per la funzione del plugin.
     *
     * @type    string
     */
    public static $hook = 'init';


    /**
     * Priorità della funzione del plugin.
     *
     * @type    int
     */
    public static $priority = 0;


    /**
     * Esegui lo script una tantum.
     *
     * @hook    self::$hook
     * @return  void
     */
    public static function run() {
        // azione una tantum va qui...

        // pulizia
        add_action('shutdown', array(__CLASS__, 'unlink'), PHP_INT_MAX);
    } // function run


    /**
     * Rimuovi il file.
     *
     * @hook    shutdown
     * @return  void
     */
    public static function unlink() {
        unlink(__FILE__);
    } // function unlink

} // class OneTimeScript

add_action(OneTimeScript::$hook, array('OneTimeScript', 'run'), OneTimeScript::$priority);

Senza i commenti e il resto, appare semplicemente così:

class OneTimeScript {
    public static $hook = 'init';
    public static $priority = 0;

    public static function run() {
        // azione una tantum va qui...
        add_action('shutdown', array(__CLASS__, 'unlink'), PHP_INT_MAX);
    } // function run

    public static function unlink() {
        unlink(__FILE__);
    } // function unlink
} // class OneTimeScript
add_action(OneTimeScript::$hook, array('OneTimeScript', 'run'), OneTimeScript::$priority);
6 feb 2014 00:01:47
0

Certamente puoi farlo, crea il tuo codice one-time come un plugin.

add_action('admin_init', 'one_time_call');
function one_time_call()
{
    /* I TUOI SCRIPT */
    deactivate_plugins('onetime/index.php'); //disattiva il plugin corrente
}

Il problema è come attivare questo plugin senza cliccare sul link Attiva?

basta aggiungere activate_plugins('onetime/index.php'); nel functions.php

oppure Usa i must use plugins, http://codex.wordpress.org/Must_Use_Plugins

Prova con diverse azioni a seconda di quando vuoi eseguire il plugin one-time,

  1. admin_init - dopo l'inizializzazione dell'admin

  2. init - inizializzazione di WordPress

  3. wp - quando WordPress è caricato

8 feb 2014 18:28:52
3

A volte ho utilizzato una funzione agganciata alla disattivazione di un plugin.

Vedi qui Aggiornare i vecchi link ai permalink personalizzati per i Custom Post Type

Dato che solo gli amministratori possono attivare i plugin, c'è un controllo delle capacità come effetto collaterale.

Non è necessario eliminare il file una volta disattivato, poiché WordPress non lo includerà più. Inoltre, se vuoi eseguirlo di nuovo puoi farlo. Basta attivarlo e disattivarlo nuovamente.

A volte ho utilizzato transient come nella risposta di @fischi. Ad esempio qui query per creare prodotti WooCommerce dalle immagini o qui Eliminare/sostituire i tag img nel contenuto dei post pubblicati automaticamente

Una combinazione di entrambi i metodi può essere un'alternativa valida.

5 feb 2014 22:14:57
Commenti

Anche questa è davvero una buona idea. Se diventa fastidioso dover sempre attivare e disattivare, potresti anche agganciare la stessa funzione all'attivazione del plugin, giusto?

fischi fischi
6 feb 2014 09:20:32

Sì, se vuoi. Tuttavia, penso che 2 clic non siano uno sforzo eccessivo per eseguire uno script una tantum. Qualsiasi altra soluzione che coinvolga comandi CLI o gestione di file (rinominare, eliminare) richiede più "lavoro". Inoltre, ogni volta che ti affidi agli hook, stai contando su variabili globali, aggiungendo un ulteriore livello di potenziali problemi riguardanti la sicurezza/prevedibilità del codice. @fischi

gmazzap gmazzap
6 feb 2014 13:00:52

Anche io non penso che due clic siano troppi, volevo solo chiedere :)

fischi fischi
6 feb 2014 14:44:25
0

Un altro modo è impostare un'opzione globale wp_option quando il lavoro è completato e verificare quella opzione ogni volta che viene eseguito l'hook init.

function my_one_time_function() {
    // Esce se il lavoro è già stato fatto.
    if ( get_option( 'my_one_time_function', '0' ) == '1' ) {
        return;
    }

    /***** ESEGUI IL TUO LAVORO UNA TANTUM *****/

    // Aggiungi o aggiorna l'opzione wp
    update_option( 'my_one_time_function', '1' );
}
add_action( 'init', 'my_one_time_function' );

Naturalmente non è necessario mantenere questo codice per sempre (anche se si tratta di una semplice lettura dal database), quindi probabilmente puoi rimuovere il codice quando il lavoro è completato. Inoltre puoi modificare manualmente il valore di questa opzione a 0 se hai bisogno di rieseguire il codice.

29 dic 2014 13:22:11
0

Utilizzare wp-cli eval-file è fantastico. Puoi persino farlo su un sistema remoto (usando un alias ssh con ‘@‘) con uno script locale.

Se hai il tuo codice in one-time.php nella directory base di WordPress e hai accesso alla riga di comando sul sistema su cui vuoi eseguirlo, puoi fare:

wp eval-file one-time.php

Se hai il file one-time.php localmente e vuoi eseguirlo su un WordPress remoto usando @, il comando sarà così:

wp @remote eval-file - < one-time.php
25 giu 2020 21:00:16
0

Il mio approccio è leggermente diverso su questo. Mi piace aggiungere il mio script temporaneo come una funzione nel file function.php del mio tema e eseguirlo su una specifica query GET.

if ( isset($_GET['linkupdate']) ) {
    add_action('init', 'link_update', 10);
}
function link_update() {
  // Script Temporaneo
   die;
}

Per eseguirlo, basta visitare l'URL "www.sitename.com/?linkupdate"

Funziona bene per me finora...

Questo metodo ha degli svantaggi? Mi chiedevo...

16 giu 2017 09:10:33
0

Utilizzo semplicemente un singolo template personalizzato per i prodotti che non sto utilizzando e che non è connesso a nulla sul server pubblico.

Ad esempio, se ho una pagina di testimonianze che non è pubblicata (in modalità bozza, o simile), ma collegata a un template di pagina singola, come single-testimonial.php - posso inserire delle funzioni lì dentro, caricare la pagina tramite preview e la funzione o qualsiasi altra cosa viene lanciata una volta sola. È anche molto facile apportare modifiche alla funzione in caso di debug.

È davvero semplice e lo preferisco rispetto all'uso di init perché ho più controllo su quando e come viene avviato. È solo una mia preferenza.

9 lug 2017 01:13:25
0

Nel caso possa essere utile, ecco cosa ho fatto e funziona bene:

add_action( 'init', 'upsubscriptions_setup');

function upsubscriptions_setup()
{
    $version = get_option('upsubscriptions_setup_version');

    // Se non è ancora stata registrata alcuna versione nel database
    if (!$version) {
        add_option('upsubscriptions_setup_version', '0.1');
        $version = get_option('upsubscriptions_setup_version');
    }

    if (version_compare($version, "0.1") <= 0) {
        // esegui operazioni
        update_option('upsubscriptions_setup_version', '0.2');
    }

    if (version_compare($version, "0.2") <= 0) {
        // esegui operazioni
        update_option('upsubscriptions_setup_version', '0.3');
    }

    if (version_compare($version, "0.3") <= 0) {
        // esegui operazioni
        update_option('upsubscriptions_setup_version', '0.4');
    }

    // ecc...
}
19 nov 2018 17:25:30