web-dev-qa-db-fra.com

Quelle est votre meilleure pratique pour exécuter des scripts uniques?

Le problème

Nous avons tous été dans une situation comme celle-ci et de nombreuses questions sur ce site nécessitent une solution de ce type. Vous devez soit mettre à jour une base de données, insérer beaucoup de données automatiquement, convertir meta_keys ou quelque chose de similaire.

Bien entendu, dans un système en fonctionnement basé sur les meilleures pratiques, cela ne devrait pas se produire.

Mais dans ce cas, j'aimerais entendre votre solution personnelle à ce problème et la raison pour laquelle vous avez choisi la vôtre.

La question

Comment implémentez-vous des scripts uniques dans votre installation WordPress (en cours d'exécution)?

Le problème ici est principalement dû aux raisons suivantes:

  • Les scripts qui insèrent des données ne doivent pas s'exécuter plus d'une fois
  • Les scripts nécessitant beaucoup de ressources ne doivent pas être exécutés à un moment où ils ne peuvent pas être surveillés
  • Ils ne devraient pas être exécutés par accident

La raison pour laquelle je demande

J'ai ma propre pratique, je vais l'afficher dans les réponses. Comme je ne sais pas si c'est la meilleure solution, j'aimerais connaître la vôtre. En outre, cette question est posée à maintes reprises dans le contexte d’autres questions, et il serait bon de disposer d’une ressource rassemblant les idées.

J'ai hâte d'apprendre de vous :)

31
fischi

Pour ma part, j'utilise une combinaison de:

  • un fichier dédié au script ponctuel
  • utilisation d'un transitoire pour empêcher le script de s'exécuter accidentellement plus d'une fois
  • en utilisant la gestion des capacités ou le contrôle de l'utilisateur pour vous assurer que le script est simplement exécuté par moi.

Structure

J'utilise un fichier (onetime.php) dans mon include-folder inc, inclus dans le functions.php et supprimé de là après utilisation.

include( 'inc/onetime.php' );

Le fichier pour le script lui-même

Dans mon onetime.php ma fonction f711_my_onetime_function() est placée. Comme cela pourrait être n'importe quelle fonction. Je suppose que votre script est testé et fonctionne correctement.

Pour contrôler l'exécution du script, j'utilise à la fois

Contrôle de capacité

Pour empêcher d'autres utilisateurs d'exécuter mon script par inadvertance:

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

ou

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

un transitoire

pour m'empêcher d'exécuter accidentellement le script plus d'une fois.

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

Le fichier d'exécution du script dans ma fonction f711_my_onetime_function() ressemblerait à ceci:

$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.
}

La raison pour laquelle j'ai défini le transitoire immédiatement après la vérification, s’il existe, c’est que je souhaite que la fonction soit exécutée après le script a été verrouillé pour pouvoir être utilisé deux fois.

Si j’ai besoin d’une sortie de ma fonction, je l’imprime sous forme de commentaire dans le pied de page ou, parfois, je filtre le contenu.

La durée de verrouillage est définie sur 10 minutes, mais peut être adaptée à vos besoins.

Nettoyer

Après l'exécution réussie de mon script, je supprime la include du functions.php et supprime le onetime.php du serveur. Comme j'ai utilisé un délai d'attente pour le transitoire, je n'ai pas besoin de nettoyer la base de données, mais vous pouvez bien sûr également supprimer le transitoire après avoir supprimé le fichier.

16
fischi

Vous pouvez aussi faire ceci:

lancez onetime.php et renommez-le après exécution.

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');
}
13
Ravinder Kumar

J'ai créé un script Phing en ligne de commande pour cela, il n'y a rien de spécial à part le chargement d'un script externe à exécuter. La raison pour laquelle je l'ai utilisé via la CLI est que:

  • Je ne veux pas le charger par erreur (besoin de taper une commande)
  • Il est sécurisé car il peut être exécuté en dehors de la racine Web. En d'autres termes, il peut affecter WP mais WP ne peut accéder au script d'aucune façon.
  • Il n'ajoute aucun code à WP ni à la base de données elle-même.

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

Vous pouvez donc utiliser Phing ou la PHP CLI et dormir la nuit. Le WP-CLI est également une bonne alternative, même si j’oublie que vous pouvez l’utiliser en dehors de la racine Web.

Comme ceci est un article populaire, voici un exemple du script: https://github.com/wycks/WordPhing (run.php)

7
Wyck

Un autre moyen assez simple d’exécuter un script unique consiste à le faire au moyen d’un plug-in MU.

Placez le code dans un fichier PHP (par exemple, one-time.php) que vous avez chargé dans le dossier de votre plugin MU (par défaut, /wp-content/mu-plugins), ajustez les droits d'accès au fichier, exécutez le plugin (c'est-à-dire, selon le hook choisi). vous devez simplement visiter le frontend/backend), et vous avez tous terminé.

Voici un passe-partout:

/**
* 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);

Sans les commentaires et le reste, cela ressemble à ceci:

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);
5
tfrommen

Parfois, j'ai utilisé une fonction accrochée à la désactivation du plugin.

Voir ici Mettre à jour les anciens liens vers les types de messages personnalisés Pretty Permalinks

Une fois que seuls les administrateurs peuvent activer les plugins, une vérification des capacités est un effet secondaire.

Il n'est pas nécessaire de supprimer le fichier une fois désactivé, il ne sera pas inclus par wordress. En dépendance, si vous voulez le courir à nouveau, vous le pouvez. Activer et désactiver à nouveau.

Et parfois j'ai utilisé transitoire utilisé comme dans @fischi answer. Par exemple. ici requête pour créer des produits woocommerce à partir d'images ou ici supprimer/remplacer les balises img dans le contenu du message pour les messages publiés automatiquement

Une combinaison des deux peut être une alternative.

4
gmazzap

Certainement, vous pouvez, créez simplement votre code temporel unique en tant que plugin.

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

Problème, comment activer ce plugin sans cliquer sur Activer le lien?

il suffit d'ajouter activate_plugins('onetime/index.php'); dans functions.php

ou Use must use plugins, http://codex.wordpress.org/Must_Use_Plugins

Essayez avec différentes actions comme lorsque vous voulez exécuter le plugin onetime,

  1. admin_init - après l'initiation de l'administrateur

  2. init - wordpress init

  3. wp - lorsque wordpress est chargé

3
Amit Sukapure

Dans des conditions idéales, je ssh sur le serveur et exécuterais la fonction moi-même en utilisant wp-cli.

Cela n’est souvent pas possible, alors j’ai tendance à définir une variable $ _GET et à l’accrocher à 'init', par exemple:

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

puis frappé

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

et désactivez le crochet quand c'est fait.

3
djb

Une autre méthode consiste à définir une option globale wp_option lorsque le travail est terminé et à rechercher cette option chaque fois que le hook d'initialisation est exécuté.

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' );

Naturellement, vous n'avez pas besoin de ce code pour toujours (même s'il s'agit d'une simple lecture de la base de données), vous pouvez donc probablement supprimer le code une fois le travail terminé. Vous pouvez également définir manuellement la valeur de cette option sur 0 si vous devez réexécuter le code.

2
Mauro Mascia

J'utilise simplement une seule page de modèle de produit personnalisé que je n'utilise pas et n'est connectée à aucun élément du serveur public.

Par exemple, si j'ai une page de témoignage qui n'est pas active (en mode brouillon ou autre), mais connectée à un modèle de page unique, par exemple single-testimonial.php - Je peux y placer des fonctions, chargez la page via une variable preview et la fonction ou tout ce qui est lancé une fois. Il est également très facile de modifier la fonction en cas de débogage.

C'est vraiment facile et je préfère utiliser plutôt init parce que j'ai plus de contrôle sur quand et comment il est lancé. Juste ma préférence.

1
bbruman

Mon approche est un peu différente à ce sujet. J'aime ajouter mon script unique en tant que fonction dans le fichier function.php de mon thème et l'exécuter sur une requête GET spécifique.

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

Pour l'exécuter, il suffit de visiter l'URL "www.sitename.com/?linkupdate"

Cela fonctionne bien pour moi jusqu'à maintenant ...

Est-ce que cette méthode a des inconvénients? Je me demandais juste...

1
Sid

Juste au cas où ça aiderait, voici ce que j'ai fait et cela fonctionne bien:

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
}
0
Adam Moss