Apa waktu yang valid untuk menggunakan current_user_can () dan fungsi terkait?

10

Selama vanilla WP core dimuat, pengguna saat ini sedang diatur di $wp-init()mana setelah memuat tema dan sebelum inithook. Ini sejalan dengan praktik fungsionalitas yang baik yang dikaitkan dengan initatau lambat.

Namun itu juga merupakan praktik umum untuk memanggil fungsi terkait, seperti lebih current_user_can() awal dari itu. Secara definisi, ini diperlukan untuk plugin yang berfungsi dengan tahapan proses pemuatan sebelumnya (plugin Toolbar Theme Switcher saya akan menjadi contoh).

Dokumentasi tidak membuat klaim untuk atau menentang praktik ini (yang dapat saya temukan).

Namun beberapa plugin tampaknya menghubungkan ke fungsi yang berhubungan dengan pengguna dan mengharapkan post- initstate setiap saat.

Misalnya bbPress melempar pemberitahuan berikut:

// If the current user is being setup before the "init" action has fired,
// strange (and difficult to debug) role/capability issues will occur.
if ( ! did_action( 'after_setup_theme' ) ) {
    _doing_it_wrong( __FUNCTION__, __( 'The current user is being initialized without using $wp->init().', 'bbpress' ), '2.3' );
}

Untuk demonstrasi cepat, buang ini ke dalam definisi inti tentang current_user_can():

function current_user_can( $capability ) {

    if ( ! did_action('after_setup_theme') ) {
        echo wp_debug_backtrace_summary();
    }

Siapa yang “benar” dalam situasi ini? Apakah ada tekad kanonik tentang penggunaan yang diizinkan / dilarang fungsi terkait pengguna sebelumnya init?

Jarang
sumber

Jawaban:

7

Satu-satunya prasyarat untuk current_user_can()yang ada wp_get_current_user(). Yang terakhir didefinisikan dalam pluggable.php, sehingga Anda dapat menggunakannya setelah plugins_loaded.

The _doing_it_wrong()panggilan Anda mengutip dalam pertanyaan Anda adalah salah untuk dirinya sendiri. Dugaan saya adalah bahwa Anda mengambilnya dari BuddyPress atau bbPress. Keduanya mengalami rekursi jika mereka tidak menunggu selama itu. Ada cara lain yang lebih baik untuk mencegah rekursi.

Dalam beberapa kasus, seperti mengubah lokal , Anda harus mengakses objek pengguna saat ini sebelumnya, jadi menunggu after_setup_themebahkan bukan opsi.

fuxia
sumber
2

Jika Anda memeriksa kemampuan pengguna sebelum initberarti ada kemungkinan Anda bertanggung jawab atas pengaturan objek pengguna saat ini.

Jika Anda mengakses pengguna setelahnya init , maka Anda yakin bahwa sesuatu yang lain sudah mengatur pengguna, sebagian besar waktu itu sendiri.

Inilah sebabnya mengapa mengakses pengguna setelah initdianggap aman .

Bahkan, akses awal mungkin mematahkan beberapa filter berjalan determine_current_user.

Patut dikatakan bahwa seseorang adalah pengait yang "rapuh", karena ada kemungkinan ia tidak pernah berjalan, dipecat hanya dalam fungsi yang dapat dicolokkan.

Namun, ada kasus (seperti @toscho berkata) di mana Anda tidak bisa menunggu sampai init, dalam kasus tersebut Anda tidak punya pilihan.

Satu-satunya cara untuk menyelesaikan ketidakcocokan adalah kasus per kasus, jika Anda mau.

Solusi yang mungkin berfungsi dalam banyak kasus (termasuk bbPress / BuddyPress) adalah menggunakan fungsi berikut alih-alih current_user_can:

function compat_current_user_can( $capability )
{
  if ( did_action( 'init' ) ) {
     return current_user_can( $capability );
  }

  $user_id = apply_filters( 'determine_current_user', false );

  return user_can( $user_id, $capability );
}

Hal ini memungkinkan untuk memeriksa kemampuan pengguna saat ini lebih awal tanpa menetapkan pengguna global, sehingga secara teori aman untuk dijalankan sebelumnya init.

Masalahnya adalah bahwa, seperti yang dikatakan di atas, kode apa pun yang menimpa fungsi yang dapat dicolokkan dan tidak memecahnya determine_current_user.

gmazzap
sumber
Saya pikir fungsi Anda memiliki variabel sedikit kacau. :)
Rarst
Ya ... mengetik terlalu cepat sebelum makan malam: P terima kasih @ialocin untuk memperbaikinya.
gmazzap
Jangan katakan itu. Selain jangan hanya mengatakan apa yang salah, perbaiki @Rarst :)
Nicolai
1

Saya cenderung berpikir bahwa BuddyPress dan bbPress harus memeriksa sesuatu yang lain sebelum mengeluarkan _doing_it_wrongpesan

Saya mengubah kedua rutinitas untuk juga memeriksa pengaturan aktual $ current_user.

global $current_user; 
if ( is_null( $current_user ) ) {
    _doing_it_wrong( ... );
}

Pemberitahuan tidak lagi ditampilkan.

Pengujian untuk did_action( "after_setup_theme" )menjadi kawat gigi untuk pergi dengan sabuk.

bobbingwide
sumber