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

32

Le problème

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

Bien sûr, dans un système en cours d'exécution basé sur les meilleures pratiques, cela ne devrait pas se produire.

Mais en même temps, j'aimerais entendre votre solution personnelle à ce problème et pourquoi vous avez choisi la vôtre.

La question

Comment implémentez-vous des scripts uniques dans votre installation (en cours) de WordPress?

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

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

La raison pour laquelle je demande

J'ai ma propre pratique, je vais la poster dans les réponses. Comme je ne sais pas si c'est la meilleure solution, j'aimerais connaître la vôtre. De plus, c'est une question qui est souvent posée dans le contexte d'autres questions, et ce serait bien d'avoir une ressource qui recueille les idées.

au plaisir d'apprendre de vous :)

fischi
la source
2
Si c'est vraiment une affaire unique, alors j'écris le script, je l'exécute, puis je le supprime. Personne ne peut plus l'exécuter après ça. Comme toutes choses, le code est éphémère. ;)
Otto
1
Le truc, c'est que je crains qu'un script ne soit appelé une deuxième fois, par coïncidence. mais j'ai fait votre approche d'innombrables fois;)
fischi
Exécutez-le sur une page d'administration d'un plugin, toujours travaillé pour moi. Vous pouvez ajouter des vérifications d'authentification en haut de la page pour vous assurer que c'est bien vous si nécessaire.
Andrew Bartel
mais vous ne parlez pas d' une exécution unique planifiée , uniquement manuelle ?
birgire
1
Oui, je ne parle que des opérations manuelles à temps, comme les scripts de migration, etc., et non wp-crondes événements planifiés.
fischi

Réponses:

17

Pour ma part, j'utilise une combinaison de:

  • un fichier dédié au script unique
  • utiliser 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 des utilisateurs pour m'assurer que le script est juste exécuté par moi.

Structure

J'utilise un fichier ( onetime.php) dans mon dossier d'inclusion inc, qui est inclus dans le functions.php, et supprimé de là après l'utilisation.

include( 'inc/onetime.php' );

Le fichier du script lui-même

Dans ma onetime.phpma 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 obtenir le contrôle de l'exécution du script, j'utilise les deux

Contrôle des capacités

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

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 pour exécuter le script dans ma fonction f711_my_onetime_function()ressemblerait à ça:

$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 est que je veux que la fonction soit exécutée après que le script a été verrouillé pour être utilisé deux fois.

Si j'ai besoin d'une sortie de ma fonction, je l'imprime en tant que commentaire dans le pied de page, ou parfois je filtre même le contenu.

Le délai de verrouillage est fixé à 10 minutes, mais peut être ajusté selon vos besoins.

Nettoyer

Après l'exécution réussie de mon script, je supprime le includedu functions.phpet le supprime onetime.phpdu 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 bien sûr, vous pouvez également supprimer le transitoire après avoir supprimé le fichier.

fischi
la source
J'ai pensé ajouter ma réponse à cela, mais après avoir lu votre liste tout en haut de cette réponse ... Je ne le ferai plus car mon approche est presque exactement la même. Donc +1 pour cela - aussi pour les réflexions détaillées à ce sujet.
tfrommen
14

Vous pouvez également le faire:

exécutez-le onetime.phpet renommez-le après l'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');
}
Ravinder Kumar
la source
Ceci est ce que nous faisons; il est à peu près garanti d'être infaillible.
Qix
7

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 l'interface CLI est la suivante:

  • Je ne veux pas qu'il se charge 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 en aucun cas atteindre le script.
  • Il n'ajoute aucun code à WP ou à 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 PHP CLI et dormir la nuit. Le WP-CLI est également une bonne alternative bien que j'oublie si vous pouvez l'utiliser en dehors de la racine Web.

Puisqu'il s'agit d'un article populaire, voici un exemple du script: https://github.com/wycks/WordPhing (run.php)

Wyck
la source
Cela semble agréable et simple, ainsi que sécurisé. Vous avez également couvert une de mes principales préoccupations (m'exécuter deux fois par accident) dans une large mesure en utilisant la ligne de commande. Bonne idée!
fischi
5

Une autre façon assez simple d'exécuter un script unique est de le faire au moyen d'un plugin MU.

Mettez le code dans un fichier PHP (par exemple, one-time.php) que vous téléchargez dans le dossier de vos plugins MU (par défaut /wp-content/mu-plugins), ajustez les autorisations du fichier, exécutez le plugin (c'est-à-dire, selon le hook que vous avez choisi, vous n'avez qu'à visiter le frontend / backend), et vous avez 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 les trucs, 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);
tfrommen
la source
4

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

Ce n'est souvent pas possible, cependant, j'ai donc tendance à définir une variable $ _GET et à la connecter à 'init', par exemple:

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

puis frappez

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

et désactivez le crochet une fois terminé.

djb
la source
4

Parfois, j'utilisais une fonction liée à la désactivation du plugin.

Voir ici Mettre à jour les anciens liens vers Pretty Permalinks Type de message personnalisé

Une fois que seuls les administrateurs peuvent activer les plugins, un contrôle 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. Dans la dépendance, si vous voulez recommencer, vous le pouvez. Activation et désactivation à nouveau.

Et parfois, j'ai utilisé des transitoires utilisés comme dans la réponse @fischi. Par exemple, ici la requête pour créer des produits de woocommerce à partir d'images ou ici Supprimer / remplacer les balises img dans le contenu des publications pour les publications publiées automatiquement

Une combinaison des deux peut être une alternative.

gmazzap
la source
C'est aussi une très bonne idée. Si cela devient ennuyeux de devoir toujours l'activer pour le désactiver à nouveau, vous pouvez également accrocher la même fonction à l'activation du plugin, non?
fischi
Oui, si tu veux. Cependant, je pense que 2 clics ne sont pas un grand effort pour exécuter un script unique. Toute autre solution qui implique la commande CLI ou la gestion de fichiers (renommer, supprimer) nécessite plus de "travail". De plus, chaque fois que vous comptez sur des hooks, vous comptez sur des variables globales, ajoutant une couche supplémentaire de problèmes potentiels concernant la sécurité / prévisibilité du code. @fischi
gmazzap
Je ne pense pas que deux clics soit trop, je voulais juste demander :)
fischi
3

Certainement, vous pouvez, créez simplement votre code 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');àfunctions.php

ou Use doit utiliser des plugins, http://codex.wordpress.org/Must_Use_Plugins

Essayez avec différentes actions comme lorsque vous souhaitez exécuter un plug-in unique,

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

  2. init - wordpress init

  3. wp - lorsque wordpress est chargé

Amit Sukapure
la source
2

Une autre façon consiste à définir une option wp_option globale lorsque le travail est terminé et à vérifier cette option à chaque exécution du 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' );

Naturellement, vous n'avez pas besoin d'avoir 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 lorsque le travail est terminé. Vous pouvez également modifier manuellement cette valeur d'option à 0 si vous devez réexécuter le code.

Mauro Mascia
la source
1

Mon approche est un peu différente à ce sujet. J'aime ajouter mon script à usage 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 exécuter cela, visitez simplement l'URL "www.sitename.com/?linkupdate"

Cela fonctionne bien pour moi jusqu'à présent ...

Cette méthode présente-t-elle des inconvénients? Je me demandais juste...

Sid
la source
1

J'utilise simplement une seule page de modèle de produit personnalisé que je n'utilise pas et qui n'est connectée à rien sur le serveur public.

Comme si j'ai une page de témoignage qui n'est pas en direct (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, charger la page via a previewet la fonction ou autre chose lancé une fois. Il est également très facile d'apporter des modifications à la fonction en cas de débogage.

C'est vraiment facile et je le préfère à l'utilisation initcar j'ai plus de contrôle sur quand et comment son lancement. Juste ma préférence.

bbruman
la source
0

Juste au cas où ça aiderait, c'est ce que j'ai fait et ça marche 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
}
Adam Moss
la source