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


32

Il problema

Siamo stati tutti in una situazione come questa e molte domande su questo sito hanno bisogno di una soluzione come questa. Devi aggiornare un database, inserire automaticamente molti dati, convertire meta_keyso qualcosa di simile.

Naturalmente, in un sistema in esecuzione basato sulle migliori pratiche ciò non dovrebbe accadere.

Ma così facendo, mi piacerebbe sentire la tua soluzione personale a questo problema e perché hai scelto la tua.

La domanda

Come si implementano gli script monouso nella propria installazione (in esecuzione) di WordPress?

Il problema qui è principalmente a causa dei seguenti motivi:

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

Il motivo che chiedo

Ho la mia pratica, la pubblicherò nelle risposte. Dato che non so se sia la migliore soluzione là fuori, mi piacerebbe sapere della tua. Inoltre, questa è una domanda che viene posta molte volte nel contesto di altre domande, e sarebbe bello avere una risorsa che raccolga le idee.

in attesa di imparare da te :)


2
Se è veramente un affare solo una volta, allora scrivo lo script, lo eseguo, quindi lo elimino. Nessuno può più eseguirlo di nuovo dopo quello. Come tutte le cose, il codice è fugace. ;)
Otto

1
Il fatto è che sono preoccupato che una sceneggiatura possa essere chiamata una seconda volta, per coincidenza. ma ho seguito il tuo approccio innumerevoli volte;)
fischi,

Eseguilo su una pagina di amministrazione di un plugin, ha sempre funzionato per me. Puoi aggiungere i controlli di autenticazione nella parte superiore della pagina per assicurarti di essere tu, se necessario.
Andrew Bartel,

ma non stai parlando dell'esecuzione programmata una sola volta, solo manuale ?
birgire,

1
Sì, sto solo parlando di operazioni manuali puntuali, come gli script di migrazione, ecc., Non di wp-croneventi programmati.
fischi,

Risposte:


17

Io stesso uso una combinazione di:

  • un file dedicato allo script monouso
  • utilizzando un transitorio per interrompere l'esecuzione accidentale dello script più di una volta
  • utilizzando la gestione delle capacità o il controllo utente per garantire che lo script sia gestito da me.

Struttura

Uso un file ( onetime.php) nella mia cartella include inc, che è incluso in functions.php, e cancellato da lì dopo l'uso.

include( 'inc/onetime.php' );

Il file per lo script stesso

Nella mia onetime.phpfunzione f711_my_onetime_function()è posto. Come potrebbe essere qualsiasi funzione. Presumo che il tuo script sia testato e funzioni correttamente.

Per ottenere il controllo sull'esecuzione dello script, uso entrambi

Controllo della capacità

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

if ( current_user_can( 'manage_options' ) ) // check for administrator rights

o

if ( get_current_user_id() == 711 ) // check if it is me - I prefer restricting the execution to me, not to all admins.

un transitorio

per impedirmi di eseguire accidentalmente lo script più di una volta.

$transient = 'f711_my_onetime_check';
if ( !get_transient( $transient ) ) // check if the function was not executed.

Il file per l'esecuzione dello script nella mia funzione f711_my_onetime_function()sarebbe simile al seguente:

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

    set_transient( $transient, 'locked', 600 ); // lock function for 10 Minutes
    add_action( 'wp_footer', 'f711_my_onetime_function' ); // execute my function on the desired hook.

}

function f711_my_onetime_function() {
    // all my glorious one-time-magic.
}

Il motivo per cui ho impostato il transitorio immediatamente dopo il controllo se esiste è che voglio che la funzione venga eseguita dopo che lo script è stato bloccato dall'essere usato due volte.

Se ho bisogno di un output dalla mia funzione, o lo stampo come commento nel piè di pagina, o a volte filtro persino il contenuto.

Il tempo di blocco è impostato su 10 minuti, ma può essere regolato in base alle proprie esigenze.

Pulire

Dopo la corretta esecuzione del mio script, elimino il includeda functions.phpe rimuovo onetime.phpdal server. Dato che ho usato un timeout per il transitorio, non ho bisogno di pulire il database, ma ovviamente potresti anche eliminare il transitorio dopo aver rimosso il file.


Ho pensato di aggiungere la mia risposta a questo, ma dopo aver letto il tuo annuncio proprio all'inizio di questa risposta ... non lo farò più poiché il mio approccio sembra quasi esattamente lo stesso. Quindi +1 per questo - anche per i pensieri dettagliati su questo.
venerdì

14

Puoi anche fare questo:

eseguirlo onetime.phpe rinominarlo dopo l'esecuzione.

if ( current_user_can( 'manage_options' ) ) {

    if( ! file_exists( '/path/to/onetime.php' ) )
      return;
    add_action( 'wp_footer', 'ravs_my_onetime_function' ); // execute my function on the desired hook.

}

function ravs_my_onetime_function() {

    // all my glorious one-time-magic.
    include( '/path/to/onetime.php' );

   // after all execution rename your file;
   rename( '/path/to/onetime.php', '/path/to/onetime-backup.php');
}

Questo è ciò che facciamo; è praticamente garantito per essere infallibile.
Qix,

7

Ho creato uno script Phing da riga di comando per questo, non è altro che caricare uno script esterno da eseguire. Il motivo per cui l'ho usato tramite l'interfaccia della riga di comando è perché:

  • Non voglio che si carichi per errore (è necessario digitare un comando)
  • È sicuro poiché può essere eseguito al di fuori della radice Web, in altre parole può influire su WP ma WP non può in alcun modo raggiungere lo script.
  • Non aggiunge alcun codice a WP o al DB stesso.

require('..path to ../wp-blog-header.php');
//bunch of WP globals
define('WP_USE_THEMES', false);
//custom code

Quindi puoi usare Phing o l'interfaccia della riga di comando di PHP e dormire di notte. La WP-CLI è anche una buona alternativa anche se dimentico se puoi usarla al di fuori della radice del web.

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


Sembra bello e semplice, oltre che sicuro. Hai anche coperto una delle mie principali preoccupazioni (eseguirmi due volte per caso) in gran parte usando la riga di comando. Bella idea!
fischi,

5

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

Inserisci il codice in alcuni file PHP (ad es. one-time.php) Che carichi nella cartella dei plug-in MU (per impostazione predefinita /wp-content/mu-plugins), regola le autorizzazioni del file, esegui il plug-in (ovvero, in base al hook scelto, in pratica devi solo visitare il frontend / backend) e il gioco è fatto.

Ecco un boilerplate:

/**
* Main (and only) class.
*/
class OneTimeScript {

    /**
     * Plugin function hook.
     *
     * @type    string
     */
    public static $hook = 'init';


    /**
     * Plugin function priority.
     *
     * @type    int
     */
    public static $priority = 0;


    /**
     * Run the one-time script.
     *
     * @hook    self::$hook
     * @return  void
     */
    public static function run() {
        // one-time action goes here...

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


    /**
     * Remove the 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 le cose, sembra proprio così:

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

    public static function run() {
        // one-time action goes here...
        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);

4

In condizioni ideali avrei usato ssh nel server ed avrei eseguito la funzione da solo usando wp-cli.

Questo spesso 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();
    }
});

quindi colpire

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

e disabilitare l'hook al termine.


4

A volte ho usato una funzione agganciata alla disattivazione del plugin.

Vedi qui Aggiorna vecchi link a Pretty Permalink Tipo di post personalizzato

Una volta che solo gli amministratori possono attivare i plug-in, esiste un controllo di capacità come effetto collaterale.

Non è necessario eliminare il file una volta disattivato che non verrà incluso da wordress. Inoltre, se vuoi eseguirlo di nuovo, puoi farlo. Attivazione e disattivazione di nuovo.

E a volte ho usato transitori usati come nella risposta @fischi. Ad esempio, qui esegui una query per creare prodotti di woocommerce dalle immagini o qui Elimina / sostituisci i tag img nel contenuto dei post per i post pubblicati automaticamente

Una combinazione di entrambi può essere un'alternativa.


Anche questa è un'ottima idea. Se diventa fastidioso dover sempre attivare per disattivarlo di nuovo, potresti anche agganciare la stessa funzione all'attivazione del plugin, giusto?
fischi,

Si se vuoi. Tuttavia, penso che 2 clic non sia un grande sforzo per eseguire uno script una tantum. Qualsiasi altra soluzione che implichi il comando CLI o la gestione dei file (ridenominazione, eliminazione) richiede più "lavoro". Inoltre, ogni volta che si fa affidamento su hook, si fa affidamento su variabili globali, aggiungendo un ulteriore livello di potenziali problemi relativi alla sicurezza / prevedibilità del codice. @fischi
gmazzap

Non penso che neanche due clic siano troppo, volevo solo chiedere :)
fischi,

3

Sicuramente puoi, basta creare il tuo codice temporale come plugin.

add_action('admin_init', 'one_time_call');
function one_time_call()
{
    /* YOUR SCRIPTS */
    deactivate_plugins('onetime/index.php'); //deactivate current plugin
}

Problema come posso attivare questo plugin senza fare clic su Attiva collegamento?

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

oppure Use deve utilizzare plugin, http://codex.wordpress.org/Must_Use_Plugins

Prova con diverse azioni come quando desideri eseguire il plug-in di una volta,

  1. admin_init - dopo admin init

  2. init - wordpress init

  3. wp - quando wordpress è stato caricato


2

Un altro modo è impostare un wp_option globale al termine del lavoro e verificare tale opzione ogni volta che viene eseguito l'hook init.

function my_one_time_function() {
    // Exit if the work has already been done.
    if ( get_option( 'my_one_time_function', '0' ) == '1' ) {
        return;
    }

    /***** DO YOUR ONE TIME WORK *****/

    // Add or update the wp_option
    update_option( 'my_one_time_function', '1' );
}
add_action( 'init', 'my_one_time_function' );

Naturalmente non è necessario avere questo codice per sempre (anche se si tratta di una semplice lettura dal database), quindi è possibile rimuoverlo probabilmente al termine del lavoro. Inoltre, è possibile modificare manualmente questo valore di opzione su 0 se è necessario rieseguire il codice.


1

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

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

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

Questo funziona bene per me fino ad ora ...

Questo metodo presenta degli svantaggi? Mi chiedo solo ...


1

Uso solo una singola pagina di modello di prodotto personalizzata che non sto utilizzando e non è connessa a nulla sul server pubblico.

Come se avessi una pagina di testimonianza che non è attiva (in modalità bozza o altro), ma collegata a un modello di pagina singola, ad esempio single-testimonial.php- Posso inserire funzioni lì, caricare la pagina tramite ae previewla funzione o qualunque cosa sia lanciato una volta. È anche molto semplice apportare modifiche alla funzione in caso di debug.

È davvero facile e preferisco usarlo initperché ho un maggiore controllo su quando e come viene lanciato. Solo la mia preferenza.


0

Nel caso in cui aiuti, questo è quello che ho fatto e funziona bene:

add_action( 'init', 'upsubscriptions_setup');

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

    // If no version is recorded yet in the DB
    if (!$version) {
        add_option('upsubscriptions_setup_version', '0.1');
        $version = get_option('upsubscriptions_setup_version');
    }

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

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

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

    // etc
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.