Яка найкраща практика для виконання одноразових сценаріїв?


32

Проблема

Ми всі опинилися в такій ситуації, і для багатьох питань на цьому сайті потрібне таке рішення. Вам або потрібно оновити базу даних, автоматично вставити багато даних, перетворити meta_keysабо щось подібне.

Звичайно, у працюючій системі, заснованій на кращих практиках, цього не повинно відбуватися.

Але, як це робиться, я хотів би почути ваше особисте рішення цієї проблеми, і чому ви вибрали своє.

Питання

Як ви реалізуєте одноразові сценарії у своїй (запущеній) програмі WordPress?

Проблема тут в основному пов'язана з наступними причинами:

  • Сценарії, які вставляють дані, не повинні працювати більше одного разу
  • Сценарії, які потребують великої кількості ресурсів, не повинні запускатися в той момент, коли їх неможливо контролювати
  • Їм не слід керувати випадково

Причину, яку я запитую

У мене є своя практика, я збираюся розмістити це у відповідях. Оскільки я не знаю, чи найкраще це рішення там, я хотів би знати про ваше. Крім того, це питання, яке задають багато разів в контексті інших питань, і було б чудово мати ресурс для збору ідей.

чекаю навчання у вас :)


2
Якщо це справді разова угода, тоді я пишу сценарій, запускаю його, потім видаляю. Після цього ніхто не може запустити його знову. Як і всі речі, код швидкоплинний. ;)
Отто

1
Справа в тому, що я переживаю, що сценарій можна назвати вдруге за збігом обставин. але я зробив ваш підхід незліченну кількість разів;)
fischi

Запустити його на адмін-сторінці плагіна, завжди працював для мене. Ви можете додати перевірки автентичності вгорі сторінки, щоб переконатися, що це ви, якщо потрібно.
Ендрю Бартель

але ви не говорите про заплановане одноразове виконання, а лише вручну ?
birgire

1
Так, я говорю лише про ручні операції в часі, такі як міграційні сценарії тощо, а не wp-cronзаплановані події.
fischi

Відповіді:


17

Я для себе використовую комбінацію:

  • один файл, присвячений одноразовому сценарію
  • використання перехідного періоду, щоб запобігти випадковому запуску сценарію не один раз
  • використовуючи управління можливостями або управління користувачем, щоб гарантувати, що сценарій просто виконується мною.

Будова

Я використовую файл ( onetime.php) у своїй папці include inc, яка входить до складу functions.phpта видаляється звідти після використання.

include( 'inc/onetime.php' );

Файл для самого сценарію

У моїй onetime.phpфункції f711_my_onetime_function()розміщена моя . Як це може бути будь-яка функція. Я припускаю, що ваш сценарій перевірений і працює правильно.

Для досягнення контролю над виконанням сценарію я використовую і те, і інше

Контроль можливостей

Щоб інші користувачі не могли випадково виконати мій сценарій:

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

або

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

перехідний

щоб зупинити себе випадково виконувати сценарій не один раз.

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

Файл для виконання сценарію в моїй функції f711_my_onetime_function()виглядатиме так:

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

Причиною того, що я встановлюю перехідний момент відразу після перевірки, чи він існує, є те, що я хочу, щоб функція виконувалася після того, як сценарій був заблокований від того, що використовується два рази.

Якщо мені потрібен якийсь вихід з моєї функції, я або роздруковую його як коментар у нижньому колонтитулі, або іноді навіть фільтрую вміст.

Час блокування встановлено на 10 хвилин, але його можна налаштувати під ваші потреби.

Прибирати

Після успішного виконання мого сценарію я видалити includeз functions.php, і видалити onetime.phpз сервера. Оскільки я використав тайм-аут для перехідного періоду, мені не потрібно очищати базу даних, але, звичайно, ви також можете видалити перехідний процес після видалення файлу.


Я думав над тим, щоб додати свою відповідь до цього, але прочитавши ваш перелік у верхній частині цієї відповіді ... я більше не буду, оскільки мій підхід виглядає майже точно так само. Тож +1 для цього - також для детальних думок з цього приводу.
tfrommen

14

Ви також можете зробити це:

запустити onetime.phpі перейменувати його після виконання.

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

Це ми робимо; це гарантовано беззаконне.
Qix

7

Я створив для цього командний рядок Phing script, це не що інше, як завантаження зовнішнього сценарію для запуску. Причина, яку я використовував через CLI, полягає в тому, що:

  • Я не хочу, щоб він завантажувався помилково (потрібно ввести команду)
  • Це безпечно, оскільки його можна запускати за межами веб-кореня, іншими словами, він може впливати на WP, але WP ніяк не може дійти до сценарію.
  • Він не додає жодного коду до WP або самої БД.

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

Таким чином, ви можете використовувати Phing або PHP CLI і спати вночі. WP-CLI також є хорошою альтернативою, хоча я забуваю, чи можна використовувати її поза корінням веб-сторінок.

Оскільки це популярна публікація, ось приклад сценарію: https://github.com/wycks/WordPhing (run.php)


Це виглядає красиво і просто, а також безпечно. Ви також охопили одну з моїх головних проблем (мене два рази випадково виконували), використовуючи командний рядок. Хороша ідея!
fischi

5

Ще один досить простий спосіб запуску одноразового сценарію - це зробити за допомогою плагіна MU.

Помістіть код у якийсь файл PHP (наприклад, one-time.php), який ви завантажуєте у папку MU плагінів (за замовчуванням /wp-content/mu-plugins), відрегулюйте дозволи файлів, запустіть плагін (тобто, відповідно до обраного вами гачка, ви, як правило, просто повинні відвідати фронтенд / бекенд), і ви все готові.

Ось котельня:

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

Без коментарів і речей, це просто виглядає так:

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

В ідеальних умовах я б сш на сервер і сам виконував цю функцію за допомогою wp-cli.

Однак це часто неможливо, тому я, як правило, встановлюю змінну $ _GET і підключаю її до 'init', наприклад:

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

потім вдарити

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

і відключити гачок, коли це зроблено.


4

Іноді я використовував функцію, підключену до деактивації плагінів.

Дивіться тут Оновлення старих посилань на досить постійні посилання Спеціальний тип пошти

Після того, як тільки адміністратори можуть активувати плагіни, є перевірка працездатності як побічний ефект.

Немає необхідності видаляти файл після його відключення, він не буде включений у wordress. У залежності від наркотиків, якщо ви хочете запустити його знову, ви можете. Знову активація та деактивація.

І іноді я використовував перехідний, який використовується, як у відповіді @fischi. Наприклад, запит для створення продуктів з комерційної торгівлі із зображень або тут Видалення / заміна тегів IMG у вмісті публікацій для автоматично опублікованих публікацій

Комбінація обох може бути альтернативою.


Це теж дійсно гарна ідея. Якщо вам стає прикро завжди постійно активувати, щоб знову його відключити, ви також можете підключити ту саму функцію до активації плагіна, правда?
fischi

Так, якщо бажаєш. Однак я вважаю, що 2 клацання не є великим зусиллям для запуску одноразового сценарію. Будь-яке інше рішення, яке передбачає обробку команд або файлів CLI (перейменування, видалення), потребує більшої роботи. Крім того, кожного разу, коли ви покладаєтесь на гачки, ви покладаєтесь на глобальні змінні, додаючи додатковий рівень потенційних проблем щодо безпеки / передбачуваності коду. @fischi
gmazzap

Я не думаю, що два кліки теж не занадто, просто хотів запитати :)
fischi

3

Однозначно ви можете, просто створіть свій одноразовий код як плагін.

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

Проблема, як активувати цей плагін, не натискаючи посилання Активувати?

просто додати activate_plugins('onetime/index.php');вfunctions.php

або Використовувати потрібно використовувати плагіни http://codex.wordpress.org/Must_Use_Plugins

Спробуйте з різними діями, як коли ви хочете виконати одноразовий плагін,

  1. admin_init - після адміністратора init

  2. init - wordpress init

  3. wp - при завантаженні wordpress


2

Інший спосіб - встановити глобальний wp_option, коли робота виконана, і перевіряти цю опцію кожного разу, коли виконується гачок 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' );

Звичайно, вам не потрібно мати цей код назавжди (навіть якщо це просте зчитування з бази даних), тому ви, ймовірно, можете видалити код, коли робота закінчена. Також ви можете вручну змінити значення цього параметра на 0, якщо вам потрібно повторно виконати код.


1

Мій підхід щодо цього трохи інший. Мені подобається додати свій одноразовий скрипт як функцію у function.php моєї теми та запустити її на конкретному GET-запиті.

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

Щоб виконати це, просто відвідайте URL-адресу "www.sitename.com/?linkupdate"

Це для мене добре працює дотепер ...

Чи є у цього методу недоліки? Просто цікаво...


1

Я просто використовую одну користувальницьку сторінку шаблону продукту, яку я не використовую і не підключена ні до чого на загальнодоступному сервері.

Наприклад, якщо у мене є сторінка відгуків, яка не є живою (у режимі чернетки чи іншим), але підключена до одного шаблону сторінки, наприклад single-testimonial.php- я можу розміщувати там функції, завантажувати сторінку за допомогою previewі функції або будь-якого іншого запущений один раз. Також дуже легко вносити зміни до функції у разі налагодження.

Це дуже просто, і я вважаю за краще використовувати його, initоскільки я маю більше контролю над тим, коли і як його запустили. Просто мої уподобання.


0

На всякий випадок, коли це допомагає, це я зробив, і це добре працює:

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
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.