Apa praktik terbaik Anda untuk menjalankan skrip satu kali?

32

Masalah

Kita semua berada dalam situasi seperti ini, dan banyak pertanyaan di situs ini membutuhkan solusi seperti ini. Anda harus memperbarui basis data, memasukkan banyak data secara otomatis, mengonversi meta_keys, atau yang serupa.

Tentu saja, dalam sistem yang berjalan berdasarkan praktik terbaik ini seharusnya tidak terjadi.

Tetapi seperti itu, saya ingin mendengar solusi pribadi Anda untuk masalah ini, dan mengapa Anda memilih solusi Anda.

Pertanyaan

Bagaimana Anda menerapkan skrip satu kali di instalasi WordPress Anda yang sedang berjalan?

Masalahnya di sini terutama karena alasan berikut:

  • Skrip yang memasukkan data tidak boleh berjalan lebih dari satu kali
  • Skrip yang membutuhkan banyak sumber daya tidak boleh dijalankan pada saat mereka tidak dapat dimonitor
  • Mereka seharusnya tidak dijalankan secara tidak sengaja

Alasan saya bertanya

Saya sudah mendapat latihan sendiri, saya akan mempostingnya di jawaban. Karena saya tidak tahu apakah itu solusi terbaik di luar sana, saya ingin tahu tentang Anda. Juga, ini adalah pertanyaan yang sering ditanyakan dalam konteks pertanyaan lain, dan alangkah baiknya memiliki sumber daya yang mengumpulkan ide-ide.

menantikan untuk belajar dari Anda :)

fischi
sumber
2
Jika itu benar-benar hanya satu kali kesepakatan, maka saya menulis skrip, saya menjalankannya, maka saya menghapusnya. Tidak ada yang bisa menjalankannya lagi setelah itu. Seperti semua hal, kode cepat berlalu. ;)
Otto
1
Masalahnya adalah saya khawatir bahwa sebuah skrip akan disebut yang kedua kalinya, per kebetulan. tapi aku melakukan pendekatanmu berkali-kali;)
fischi
Jalankan di halaman admin plugin, selalu berhasil untuk saya. Anda dapat menambahkan pemeriksaan auth di bagian atas halaman untuk memastikan itu adalah Anda jika perlu.
Andrew Bartel
tetapi Anda tidak berbicara tentang eksekusi satu kali yang dijadwalkan , hanya manual ?
birgire
1
Ya, saya hanya berbicara tentang operasi tepat waktu manual, seperti skrip migrasi, dll., Bukan wp-cronacara terjadwal.
fischi

Jawaban:

17

Saya sendiri menggunakan kombinasi:

  • satu file yang didedikasikan untuk skrip satu kali
  • menggunakan transient untuk menghentikan skrip agar tidak sengaja berjalan lebih dari satu kali
  • menggunakan manajemen kemampuan atau kontrol pengguna untuk memastikan skrip dijalankan oleh saya.

Struktur

Saya menggunakan file ( onetime.php) di folder sertakan saya inc, yang termasuk dalam functions.php, dan dihapus dari sana setelah digunakan.

include( 'inc/onetime.php' );

File untuk skrip itu sendiri

Dalam onetime.phpfungsi saya f711_my_onetime_function()ditempatkan. Karena bisa jadi fungsi apa saja. Saya menganggap skrip Anda telah diuji dan berfungsi dengan benar.

Untuk mencapai kontrol atas eksekusi skrip, saya menggunakan keduanya

Kontrol kemampuan

Untuk menghentikan pengguna lain yang tidak sengaja mengeksekusi skrip saya:

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

atau

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

sementara

untuk menghentikan diri saya sendiri secara tidak sengaja mengeksekusi skrip lebih dari sekali.

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

File untuk mengeksekusi skrip di fungsi saya f711_my_onetime_function()akan terlihat seperti itu:

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

Alasan saya mengatur transient segera setelah pemeriksaan jika ada adalah bahwa saya ingin fungsi dieksekusi setelah skrip dikunci dari beeing digunakan dua kali.

Jika saya memerlukan output dari fungsi saya, saya mencetaknya sebagai komentar di catatan kaki, atau kadang-kadang saya bahkan memfilter konten.

Waktu penguncian diatur ke 10 Menit, tetapi dapat disesuaikan dengan kebutuhan Anda.

Membersihkan

Setelah eksekusi skrip saya berhasil, saya menghapus includedari functions.php, dan menghapus onetime.phpdari server. Karena saya menggunakan batas waktu untuk transient, saya tidak perlu membersihkan database, tetapi tentu saja Anda juga bisa menghapus transient setelah Anda menghapus file.

fischi
sumber
Saya berpikir untuk menambahkan jawaban saya ke ini, tetapi setelah membaca daftar Anda tepat di bagian atas jawaban ini ... Saya tidak akan lagi karena pendekatan saya terlihat hampir persis sama. Jadi +1 untuk ini - juga untuk pemikiran terperinci tentang ini.
tfrommen
14

Anda juga dapat melakukan ini:

jalankan onetime.phpdan ganti nama setelah eksekusi.

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
sumber
Inilah yang kami lakukan; itu cukup dijamin untuk menjadi bukti bodoh.
Qix
7

Saya membuat skrip baris perintah Phing untuk ini, tidak ada yang istimewa selain memuat skrip eksternal untuk dijalankan. Alasan saya menggunakannya melalui CLI adalah karena:

  • Saya tidak ingin memuat secara tidak sengaja (perlu mengetikkan perintah)
  • Ini aman karena dapat dijalankan di luar root web, dengan kata lain itu dapat mempengaruhi WP tetapi WP tidak dapat mencapai script dengan cara apa pun.
  • Itu tidak menambahkan kode apa pun ke WP atau DB itu sendiri.

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

Jadi Anda bisa menggunakan Phing, atau PHP CLI dan tidur di malam hari. WP-CLI juga merupakan alternatif yang baik meskipun saya lupa jika Anda dapat menggunakannya di luar root web.

Karena ini adalah posting populer di sini adalah contoh skrip: https://github.com/wycks/WordPhing (run.php)

Wyck
sumber
Ini terlihat bagus dan sederhana, serta aman. Anda juga membahas salah satu masalah utama saya (saya mengeksekusi dua kali secara tidak sengaja) hingga cukup dengan menggunakan baris perintah. Ide bagus!
fischi
5

Cara lain yang cukup sederhana untuk menjalankan skrip satu kali adalah dengan melakukan ini dengan menggunakan plugin MU.

Masukkan kode dalam beberapa file PHP (mis., one-time.php) Yang Anda unggah ke folder plugin MU Anda (secara default /wp-content/mu-plugins), sesuaikan izin file, jalankan plugin (yaitu, sesuai dengan kail yang Anda pilih, Anda pada dasarnya hanya harus mengunjungi frontend / backend), dan Anda sudah selesai.

Berikut adalah 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);

Tanpa komentar dan hal-hal, itu hanya terlihat seperti ini:

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);
para pria
sumber
4

Dalam kondisi ideal saya akan ssh ke server dan menjalankan fungsinya sendiri menggunakan wp-cli.

Ini sering tidak mungkin, jadi saya cenderung untuk menetapkan variabel $ _GET dan menghubungkannya ke 'init', misalnya:

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

lalu tekan

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

dan nonaktifkan kail setelah selesai.

djb
sumber
4

Terkadang saya menggunakan fungsi yang dikaitkan pada penonaktifan plugin.

Lihat di sini Perbarui Tautan Lama Ke Pretty Tautkan Jenis Tulisan Kustom

Setelah hanya admin yang dapat mengaktifkan plugin, ada pemeriksaan kemampuan sebagai efek samping.

Tidak perlu menghapus file begitu dinonaktifkan tidak akan disertakan oleh wordress. Dalam kecanduan jika Anda ingin menjalankannya lagi Anda bisa. Mengaktifkan dan menonaktifkan lagi.

Dan terkadang saya menggunakan transient yang digunakan seperti pada jawaban @fischi. Misalnya di sini kueri untuk membuat produk woocommerce dari gambar atau di sini Hapus / ganti tag img dalam konten posting untuk posting yang dipublikasikan secara otomatis

Kombinasi keduanya bisa menjadi alternatif.

gmazzap
sumber
Ini juga Ide yang sangat bagus. Jika menjadi menjengkelkan selalu harus diaktifkan untuk menonaktifkannya lagi, Anda juga bisa mengaitkan fungsi yang sama ke aktivasi plugin, kan?
fischi
Ya, jika Anda mau. Namun, saya pikir 2 klik bukan upaya yang bagus untuk menjalankan skrip satu kali. Solusi lain apa pun yang melibatkan perintah CLI atau penanganan file (penggantian nama, penghapusan) membutuhkan lebih banyak "kerja". Selain itu, setiap kali Anda mengandalkan kait, Anda mengandalkan variabel global, menambahkan lapisan tambahan masalah potensial terkait keamanan / prediktabilitas kode. @fischi
gmazzap
Saya tidak berpikir bahwa dua klik terlalu banyak, hanya ingin bertanya :)
fischi
3

Pasti Anda bisa, Cukup buat kode waktu Anda sebagai plugin.

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

Masalah bagaimana cara mengaktifkan plugin ini tanpa mengklik tautan Aktifkan?

hanya menambahkan activate_plugins('onetime/index.php');difunctions.php

atau Penggunaan harus menggunakan plugin, http://codex.wordpress.org/Must_Use_Plugins

Coba dengan tindakan berbeda seperti ketika Anda ingin menjalankan plugin sekali pakai,

  1. admin_init - setelah admin init

  2. init - wordpress init

  3. wp - saat wordpress dimuat

Amit Sukapure
sumber
2

Cara lain adalah dengan menetapkan global wp_option ketika pekerjaan selesai dan periksa opsi itu setiap kali init hook dieksekusi.

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

Tentu saja Anda tidak perlu memiliki kode ini selamanya (bahkan jika itu adalah bacaan sederhana dari database), jadi Anda mungkin dapat menghapus kode ketika pekerjaan selesai. Anda juga dapat secara manual mengubah nilai opsi ini menjadi 0 jika Anda perlu menjalankan kembali kode tersebut.

Mauro Mascia
sumber
1

Pendekatan saya sedikit berbeda dalam hal ini. Saya ingin menambahkan skrip satu kali sebagai fungsi dalam function.php tema saya dan menjalankannya pada kueri GET tertentu.

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

Untuk menjalankan ini, cukup kunjungi URL "www.sitename.com/?linkupdate"

Ini bekerja dengan baik untuk saya sampai sekarang ...

Apakah metode ini memiliki kekurangan? Hanya ingin tahu...

Sid
sumber
1

Saya hanya menggunakan satu halaman templat produk khusus yang tidak saya gunakan dan tidak terhubung dengan apa pun di server publik.

Seperti jika saya memiliki halaman testimonial yang tidak langsung (dalam mode konsep, atau apa pun), tetapi terhubung ke template halaman tunggal, misalnya single-testimonial.php- Saya dapat menempatkan fungsi di sana, memuat halaman melalui a previewdan fungsi atau apa pun yang ada diluncurkan sekali. Ini juga sangat mudah untuk membuat modifikasi pada fungsi jika terjadi debugging.

Sangat mudah dan saya lebih suka daripada menggunakan initkarena saya memiliki lebih banyak kontrol kapan dan bagaimana diluncurkan. Hanya preferensi saya.

bbruman
sumber
0

Kalau-kalau itu membantu, ini adalah apa yang saya lakukan dan itu bekerja dengan baik:

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
sumber