Care este cea mai bună practică pentru a executa scripturi one-time?

29 ian. 2014, 18:24:47
Vizualizări: 21.4K
Voturi: 42

Problema

Cu toții am fost într-o situație de acest gen, și multe întrebări de pe acest site necesită o soluție similară. Fie trebuie să actualizați o bază de date, să inserați automat o mulțime de date, să convertiți meta_keys, sau ceva asemănător.

Desigur, într-un sistem funcțional bazat pe cele mai bune practici, acest lucru nu ar trebui să se întâmple.

Dar pentru că se întâmplă, mi-ar plăcea să aud soluția voastră personală la această problemă și de ce ați ales-o.

Întrebarea

Cum implementați scripturile one-time în instalarea voastră WordPress (în funcțiune)?

Problema apare în principal din următoarele motive:

  • Scripturile care inserează date nu ar trebui să ruleze mai mult de o singură dată
  • Scripturile care necesită multe resurse nu ar trebui să ruleze într-un moment în care nu pot fi monitorizate
  • Nu ar trebui să fie executate din greșeală

Motivul pentru care întreb

Am propria mea practică, pe care o voi posta în răspunsuri. Deoarece nu știu dacă este cea mai bună soluție disponibilă, aș dori să aflu despre a voastră. De asemenea, aceasta este o întrebare care este pusă de multe ori în contextul altor întrebări, și ar fi grozav să avem o resursă care să colecteze ideile.

aștept cu nerăbdare să învăț de la voi :)

8
Comentarii

Dacă este cu adevărat o afacere de o singură dată, atunci scriu scriptul, îl rulez, apoi îl șterg. Nimeni nu îl mai poate rula după aceea. Ca toate lucrurile, codul este efemer. ;)

Otto Otto
29 ian. 2014 20:44:20

Problema este că mă tem că un script ar putea fi apelat a doua oară, din coincidență. Dar am folosit abordarea ta de nenumărate ori ;)

fischi fischi
29 ian. 2014 22:31:21

Rulează-l pe o pagină de admin a unui plugin, a funcționat întotdeauna pentru mine. Poți adăuga verificări de autorizare în partea de sus a paginii pentru a te asigura că ești tu, dacă este necesar.

Andrew Bartel Andrew Bartel
29 ian. 2014 23:14:15

dar nu vorbești despre execuția programată o singură dată, ci doar despre cea manuală?

birgire birgire
3 feb. 2014 13:08:42

Da, mă refer doar la operațiuni manuale unice, cum ar fi scripturile de migrare etc., nu la evenimente programate prin wp-cron.

fischi fischi
3 feb. 2014 14:10:32

Presupun că nu înțeleg de ce ai vrea să faci asta. Dacă vrei să schimbi numele unei meta_key folosite atât în baza de date cât și în cod, există cu adevărat un script care să facă totul într-o singură rulare? Chiar dacă nu ar fi nevoie să schimbi baza de date și doar codul, dacă ai include un script prin include, acesta nu ar rămâne neschimbat până când pagina este apelată? Cred că nu înțeleg ideea :/

Howdy_McGee Howdy_McGee
5 feb. 2014 23:00:55

Ideea este, de exemplu, să convertești informațiile SEO de la un plugin la altul, fără a pierde informații sau a insera o mulțime de conținut - ceea ce trebuie să ruleze doar o singură dată. Și cu funcțiile încorporate în WordPress, ești mult mai rapid și mai sigur decât să rulezi interogări în baza ta de date.

fischi fischi
6 feb. 2014 09:11:51

Nu a fost scopul meu să fac asta - dar după vot voi alege răspunsul meu, bazat exclusiv pe rezultate.

fischi fischi
11 feb. 2014 08:22:55
Arată celelalte 3 comentarii
Toate răspunsurile la întrebare 12
1
26

Eu personal folosesc o combinație de:

  • un fișier dedicat pentru scriptul de unică folosință
  • folosirea unui transient pentru a împiedica rularea accidentală a scriptului de mai multe ori
  • folosirea managementului de capabilități sau controlului utilizatorilor pentru a mă asigura că scriptul este rulat doar de mine.

Structură

Folosesc un fișier (onetime.php) în directorul meu de include inc, care este inclus în functions.php, și șters de acolo după utilizare.

include( 'inc/onetime.php' );

Fișierul pentru scriptul propriu-zis

În onetime.php se află funcția mea f711_my_onetime_function(). Aceasta poate fi orice funcție. Presupun că scriptul tău este testat și funcționează corect.

Pentru a controla execuția scriptului, folosesc ambele metode:

Controlul capabilităților

Pentru a împiedica alți utilizatori să ruleze accidental scriptul meu:

if ( current_user_can( 'manage_options' ) ) // verifică drepturile de administrator

sau

if ( get_current_user_id() == 711 ) ) // verifică dacă sunt eu - prefer să restricționez execuția doar pentru mine, nu pentru toți adminii.

un transient

pentru a mă împiedica pe mine să rulez accidental scriptul de mai multe ori.

$transient = 'f711_my_onetime_check';
if ( !get_transient( $transient ) ) ) // verifică dacă funcția nu a fost executată.

Fișierul pentru execuția scriptului în funcția mea f711_my_onetime_function() ar arăta astfel:

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

    set_transient( $transient, 'locked', 600 ); // blochează funcția pentru 10 minute
    add_action( 'wp_footer', 'f711_my_onetime_function' ); // execută funcția mea pe hook-ul dorit.

}

function f711_my_onetime_function() {
    // toată magia mea de unică folosință.
}

Motivul pentru care setez transient imediat după verificarea existenței acestuia este că vreau ca funcția să fie executată după ce scriptul a fost blocat pentru a nu fi folosit de două ori.

Dacă am nevoie de vreun output din funcția mea, îl afișez fie ca un comentariu în footer, fie uneori filtrez conținutul.

Timpul de blocare este setat la 10 minute, dar poate fi ajustat după nevoie.

Curățare

După execuția cu succes a scriptului meu, șterg include-ul din functions.php și elimin onetime.php de pe server. Deoarece am folosit un timeout pentru transient, nu este nevoie să curăț baza de date, dar desigur poți șterge și transient-ul după ce ai eliminat fișierul.

29 ian. 2014 18:24:47
Comentarii

M-am gândit să adaug și eu răspunsul meu la asta, dar după ce am citit lista ta chiar în partea de sus a acestui răspuns... nu o voi mai face, deoarece abordarea mea arată aproape la fel. Așadar, +1 pentru asta - și pentru gândurile detaliate pe această temă.

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

Puteți face și asta:

rulați onetime.php și redenumiți fișierul după execuție.

if ( current_user_can( 'manage_options' ) ) {

    if( ! file_exists( '/path/to/onetime.php' ) )
      return;
    add_action( 'wp_footer', 'ravs_my_onetime_function' ); // execută funcția mea pe hook-ul dorit.

}

function ravs_my_onetime_function() {

    // toată magia mea de unică folosință.
    include( '/path/to/onetime.php' );

   // după execuție redenumește fișierul;
   rename( '/path/to/onetime.php', '/path/to/onetime-backup.php');
}
5 feb. 2014 21:58:56
Comentarii

Asta este ceea ce facem; este garantat să fie infailibil.

Qix - MONICA WAS MISTREATED Qix - MONICA WAS MISTREATED
6 ian. 2015 23:07:52

Perfect, nu știu de ce nu mi-a venit această idee în minte, Mulțumesc :)

Shahin Shahin
11 feb. 2020 09:01:46
1

Am creat un script Phing pentru linia de comandă pentru asta, nu este nimic special în afară de încărcarea unui script extern pentru rulare. Motivul pentru care l-am folosit prin CLI este următorul:

  • Nu vreau să se încarce din greșeală (trebuie tastată o comandă)
  • Este sigur deoarece poate fi rulat în afara rădăcinii web, cu alte cuvinte poate afecta WP dar WP nu poate accesa scriptul în niciun fel.
  • Nu adaugă niciun cod suplimentar în WP sau în baza de date.

require('..cale către ../wp-blog-header.php');
//o grămadă de variabile globale WP
define('WP_USE_THEMES', false);
//cod personalizat

Deci poți folosi Phing sau PHP CLI și poți dormi liniștit. WP-CLI este de asemenea o alternativă bună, deși nu mai țin minte dacă poate fi folosit în afara rădăcinii web.

Deoarece acesta este un post popular, iată un exemplu de script: https://github.com/wycks/WordPhing (run.php)

6 feb. 2014 04:54:58
Comentarii

Arată frumos și simplu, la fel de sigur. Ai acoperit și una dintre preocupările mele principale (executarea accidentală de două ori) într-o mare măsură prin utilizarea liniei de comandă. Bună idee!

fischi fischi
6 feb. 2014 09:18:15
0

În condiții ideale, m-aș conecta prin SSH la server și aș executa funcția manual folosind wp-cli.

Totuși, acest lucru nu este întotdeauna posibil, așa că de obicei setez o variabilă $_GET și o atașez la acțiunea 'init', de exemplu:

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

apoi accesez

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

și dezactivez hook-ul când acțiunea este finalizată.

5 feb. 2014 21:38:38
0

O altă metodă destul de simplă de a rula un script o singură dată este să faci acest lucru prin intermediul unui plugin MU.

Pune codul într-un fișier PHP (de exemplu, one-time.php) pe care îl încarci în folderul de MU plugins (implicit /wp-content/mu-plugins), ajustează permisiunile fișierului, rulează pluginul (adică, conform hook-ului ales, practic trebuie doar să vizitezi frontend-ul/backend-ul), și ai terminat.

Aici este un șablon:

/**
* Clasa principală (și singura).
*/
class OneTimeScript {

    /**
     * Hook-ul funcției pluginului.
     *
     * @type    string
     */
    public static $hook = 'init';


    /**
     * Prioritatea funcției pluginului.
     *
     * @type    int
     */
    public static $priority = 0;


    /**
     * Rulează scriptul o singură dată.
     *
     * @hook    self::$hook
     * @return  void
     */
    public static function run() {
        // acțiunea de o singură dată se adaugă aici...

        // curăță
        add_action('shutdown', array(__CLASS__, 'unlink'), PHP_INT_MAX);
    } // funcția run


    /**
     * Șterge fișierul.
     *
     * @hook    shutdown
     * @return  void
     */
    public static function unlink() {
        unlink(__FILE__);
    } // funcția unlink

} // clasa OneTimeScript

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

Fără comentarii și altele, arată astfel:

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

    public static function run() {
        // acțiunea de o singură dată se adaugă aici...
        add_action('shutdown', array(__CLASS__, 'unlink'), PHP_INT_MAX);
    } // funcția run

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

Desigur că poți, creează-ți propriul cod one-time ca un plugin.

add_action('admin_init', 'one_time_call');
function one_time_call()
{
    /* SCRIPTURILE TALE */
    deactivate_plugins('onetime/index.php'); //dezactivează pluginul curent
}

Problema este cum activez acest plugin fără să apăs pe linkul Activate?

pur și simplu adaugă activate_plugins('onetime/index.php'); în functions.php

sau Folosește must use plugins, http://codex.wordpress.org/Must_Use_Plugins

Încearcă cu diferite acțiuni în funcție de când vrei să execuți pluginul one-time,

  1. admin_init - după inițializarea admin-ului

  2. init - inițializarea WordPress

  3. wp - când WordPress este încărcat

8 feb. 2014 18:28:52
3

Uneori am folosit o funcție legată de dezactivarea pluginului.

Vezi aici Actualizare legături vechi la permalinkuri personalizate pentru tipuri de postare

Deoarece doar administratorii pot activa pluginuri, există o verificare a capabilității ca efect secundar.

Nu este nevoie să ștergi fișierul odată dezactivat, acesta nu va fi inclus de WordPress. În plus, dacă dorești să o rulezi din nou, poți face acest lucru prin activarea și dezactivarea din nou.

Și uneori am folosit transient-uri ca în răspunsul lui @fischi. De exemplu aici interogare pentru creare produse WooCommerce din imagini sau aici Șterge/înlocuiește tag-uri img în conținutul postărilor pentru postări publicate automat

O combinație dintre cele două poate fi o alternativă.

5 feb. 2014 22:14:57
Comentarii

Aceasta este de asemenea o idee foarte bună. Dacă devine enervant să tot activezi și dezactivezi funcționalitatea, ai putea să folosești același hook și la activarea plugin-ului, nu-i așa?

fischi fischi
6 feb. 2014 09:20:32

Da, dacă dorești. Totuși, cred că 2 click-uri nu reprezintă un efort prea mare pentru a rula un script o singură dată. Orice altă soluție care implică comenzi CLI sau manipulare de fișiere (redenumire, ștergere) necesită mai multă "muncă". În plus, de fiecare dată când te bazezi pe hooks, te bazezi pe variabile globale, adăugând un strat suplimentar de potențiale probleme legate de securitate/predictibilitatea codului. @fischi

gmazzap gmazzap
6 feb. 2014 13:00:52

Nici eu nu cred că două click-uri sunt prea mult, doar am vrut să întreb :)

fischi fischi
6 feb. 2014 14:44:25
0

O altă metodă este să setezi o opțiune globală wp_option când sarcina este finalizată și să verifici această opțiune de fiecare dată când acțiunea init este executată.

function my_one_time_function() {
    // Ieși dacă sarcina a fost deja efectuată.
    if ( get_option( 'my_one_time_function', '0' ) == '1' ) {
        return;
    }

    /***** EXECUTĂ SARCINA TA O SINGURĂ DATĂ *****/

    // Adaugă sau actualizează opțiunea wp_option
    update_option( 'my_one_time_function', '1' );
}
add_action( 'init', 'my_one_time_function' );

Desigur, nu este necesar să păstrezi acest cod pentru totdeauna (chiar dacă este doar o simplă citire din baza de date), așa că îl poți elimina după ce sarcina este finalizată. De asemenea, poți modifica manual valoarea acestei opțiuni la 0 dacă ai nevoie să re-executi codul.

29 dec. 2014 13:22:11
0

Folosirea comenzii wp-cli eval-file este foarte utilă. Poți chiar să o execuți pe un sistem la distanță (folosind un alias ssh '@') cu un script local.

Dacă ai codul tău în fișierul one-time.php în directorul de bază WordPress și ai acces la linia de comandă pe sistemul pe care vrei să-l rulezi, poți face:

wp eval-file one-time.php

Dacă ai fișierul one-time.php local și vrei să-l rulezi pe un WordPress la distanță folosind @, arată astfel:

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

Abordarea mea este puțin diferită în acest caz. Îmi place să adaug scripturile mele unice ca funcții în fișierul functions.php al temei mele și să le rulez pe baza unei interogări GET specifice.

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

Pentru a rula acest script, pur și simplu accesează URL-ul "www.sitename.com/?linkupdate"

Această metodă a funcționat bine pentru mine până acum...

Există vreun dezavantaj la această abordare? Mă întrebam doar...

16 iun. 2017 09:10:33
0

Eu folosesc doar o singură pagină șablon personalizată pentru produse pe care nu o folosesc și care nu este conectată la nimic pe serverul public.

De exemplu, dacă am o pagină de testimonialuri care nu este live (în modul draft sau altceva), dar este conectată la un șablon de pagină unic, cum ar fi single-testimonial.php - pot să adaug funcții acolo, să încărc pagina prin intermediul unei previzualizări iar funcția sau orice altceva este lansată o singură dată. Este de asemenea foarte ușor să fac modificări la funcție în cazul depanării.

Este foarte ușor și prefer asta în loc să folosesc init pentru că am mai mult control asupra momentului și modului în care este lansată. Doar preferința mea.

9 iul. 2017 01:13:25
0

Doar în caz că ajută, iată ce am făcut eu și funcționează bine:

add_action( 'init', 'upsubscriptions_setup');

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

    // Dacă încă nu există o versiune înregistrată în baza de date
    if (!$version) {
        add_option('upsubscriptions_setup_version', '0.1');
        $version = get_option('upsubscriptions_setup_version');
    }

    if (version_compare($version, "0.1") <= 0) {
        // executați acțiuni
        update_option('upsubscriptions_setup_version', '0.2');
    }

    if (version_compare($version, "0.2") <= 0) {
        // executați acțiuni
        update_option('upsubscriptions_setup_version', '0.3');
    }

    if (version_compare($version, "0.3") <= 0) {
        // executați acțiuni
        update_option('upsubscriptions_setup_version', '0.4');
    }

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