Tambahkan validasi dan penanganan kesalahan saat menyimpan bidang khusus?

27

Saya memiliki fungsi yang mendefinisikan bidang khusus pada jenis posting. Katakanlah bidangnya adalah "subjudul".

Ketika posting disimpan, saya ingin melakukan validasi pada input, dan menampilkan pesan kesalahan pada layar edit posting jika perlu. Sesuatu seperti:

// Handle post updating
function wpse_update_post_custom_values($post_id, $post) {

    // Do some checking...
    if($_POST['subhead'] != 'value i expect') {

        // Add an error here
        $errors->add('oops', 'There was an error.');

    }

    return $errors;

} 
add_action('save_post','wpse_update_post_custom_values',1,2);

Saya mencoba mengaitkan ini dengan tindakan save_post, tapi saya tidak tahu cara menangani kesalahan. Tampaknya tidak ada objek kesalahan yang diteruskan ke fungsi, dan jika saya membuat objek WP_Error saya sendiri dan mengembalikannya, itu tidak dihormati oleh mekanisme apa pun yang meludahkan kesalahan pada halaman edit posting.

Saat ini saya memiliki pesan kesalahan pada halaman di dalam kotak meta khusus saya, tetapi ini kurang dari ideal - Saya lebih suka memiliki kesalahan besar, merah, atas-di-the-top seperti yang biasanya ditampilkan WP.

Ada ide?

MEMPERBARUI:

Berdasarkan jawaban @Denis, saya mencoba beberapa hal berbeda. Menyimpan kesalahan sebagai global tidak berfungsi, karena Wordpress melakukan redirect selama proses save_post, yang membunuh global sebelum Anda dapat menampilkannya.

Saya akhirnya menyimpannya di bidang meta. Masalah dengan ini adalah bahwa Anda perlu menghapusnya, atau mereka tidak akan hilang ketika Anda menavigasi ke halaman lain, jadi saya harus menambahkan fungsi lain yang melekat pada admin_footer yang baru saja menghapus kesalahan.

Saya tidak mengira bahwa penanganan kesalahan untuk sesuatu yang sangat umum (memperbarui posting) akan menjadi kikuk ini. Apakah saya kehilangan sesuatu yang jelas atau ini pendekatan terbaik?

// Handle post updating
function wpse_5102_update_post_custom_values($post_id, $post) {

    // To keep the errors in
    $errors = false;

    // Do some validation...
    if($_POST['subhead'] != 'value i expect') {

        // Add an error here
        $errors .= 'whoops...there was an error.';

    }

    update_option('my_admin_errors', $errors);

    return;

} 
add_action('save_post','wpse_5102_update_post_custom_values',1,2);


// Display any errors
function wpse_5102_admin_notice_handler() {

    $errors = get_option('my_admin_errors');

    if($errors) {

        echo '<div class="error"><p>' . $errors . '</p></div>';

    }   

}
add_action( 'admin_notices', 'wpse_5102_admin_notice_handler' );


// Clear any errors
function wpse_5102__clear_errors() {

    update_option('my_admin_errors', false);

}
add_action( 'admin_footer', 'wpse_5102_clear_errors' );
MathSmath
sumber
Pertanyaan bagus. Saya pikir Anda bisa menyingkirkan admin_footerhook jika Anda menghapus kesalahan di akhir fungsi handler pemberitahuan Anda. Menyederhanakan hal-hal sedikit saja.
Geert
Bagaimana Anda berhadapan dengan pengisian ulang bidang formulir (dengan kemungkinan data tidak valid)?
Geert
Saya punya pertanyaan mendasar. Apa file php Wordpress ini?
@ Karen Ini akan berupa file plugin khusus, atau di functions.php Anda.
MathSmath
Saya mungkin kehilangan sesuatu yang jelas, tetapi apakah itu akan sedikit lebih efisien untuk berjalan update_option('my_admin_errors', false);segera setelah pernyataan if pada akhir wpse_5102_admin_notice_handler()?
Andrew Odri

Jawaban:

6

Simpan kesalahan di kelas Anda atau sebagai global, mungkin dalam transient atau meta, dan tampilkan dalam pemberitahuan admin pada permintaan POST. WP tidak memiliki fitur penangan pesan flash.

Denis de Bernardy
sumber
Terima kasih telah menunjukkan saya ke arah ini! Saya akhirnya menggunakan meta untuk menyimpan kesalahan, karena saya punya masalah mencoba melakukannya sebagai global atau properti. Saya sedang memperbarui jawaban saya sekarang untuk menjelaskan bagaimana saya melakukannya ... tolong beri tahu saya jika ini adalah jenis hal yang Anda sarankan, atau jika ada cara yang lebih baik yang tidak saya dapatkan.
MathSmath
Hal semacam itu, ya. Mungkin menyimpannya dalam variabel sesi, pada pikiran kedua, meskipun. Ini, untuk memungkinkan banyak penulis mengedit posting secara bersamaan. :-) Juga, saya percaya itu tidak mungkin untuk menyimpan false dalam suatu opsi. Simpan string kosong sebagai gantinya.
Denis de Bernardy
6

Saya menyarankan untuk menggunakan sesi karena ini tidak akan membuat efek aneh ketika dua pengguna mengedit secara bersamaan. Jadi inilah yang saya lakukan:

Sesi tidak dimulai oleh wordpress. Jadi, Anda perlu memulai sesi di plugin Anda, functions.php atau bahkan wp-config.php:

if (!session_id())
  session_start();

Saat menyimpan posting, tambahkan kesalahan dan pemberitahuan ke sesi:

function my_save_post($post_id, $post) {
   if($something_went_wrong) {
     //Append error notice if something went wrong
     $_SESSION['my_admin_notices'] .= '<div class="error"><p>This or that went wrong</p></div>';
     return false; //might stop processing here
   }
   if($somthing_to_notice) {  //i.e. successful saving
     //Append notice if something went wrong
     $_SESSION['my_admin_notices'] .= '<div class="updated"><p>Post updated</p></div>';
   }

   return true;
} 
add_action('save_post','my_save_post');

Cetak pemberitahuan dan kesalahan lalu bersihkan pesan di sesi:

function my_admin_notices(){
  if(!empty($_SESSION['my_admin_notices'])) print  $_SESSION['my_admin_notices'];
  unset ($_SESSION['my_admin_notices']);
}
add_action( 'admin_notices', 'my_admin_notices' );
davidn
sumber
perbaiki untuk versi sesi: pada saat pertama kali menggunakan variabel sesi tidak digunakan. = hanya = jika Anda menghidupkan debugging, Anda dapat memeriksa mengapa ...
3
Saya sudah melakukan ini juga, tetapi jika Anda merilis sebuah plugin ke khalayak luas seperti itu orang akan akhirnya membenci Anda karenanya. Wordpress tidak instantiate sesi karena dirancang untuk menjadi stateless dan tidak membutuhkannya, dan beberapa pengaturan server aneh akan merusaknya. Gunakan transients API - codex.wordpress.org/Transients_API sebagai ganti sesi dan Anda akan mempertahankan kompatibilitas. Hanya berpikir itu layak ditandai alasan mengapa tidak melakukan ini di sini.
pospi
@pospi ini tampaknya memiliki masalah yang sama dengan penggunaan asli fungsi get_option dan update_option. Jadi saya kira solusinya adalah dengan menambahkan ID pengguna saat ini ke kunci?
Gazillion
Ya itu akan berhasil! Selama Anda menambahkan sesuatu untuk mengidentifikasi pengguna secara unik, Anda akan menghindari pesan-pesan yang tercampur di antara pengguna yang masuk (:
pospi
5

Berdasarkan pospi 's saran untuk digunakan transien , saya datang dengan berikut ini. Satu-satunya masalah adalah tidak ada kait untuk meletakkan pesan di bawah h2tempat pesan lain pergi, jadi saya harus melakukan hack jQuery untuk mendapatkannya di sana.

Pertama, simpan pesan kesalahan yang ada pada save_postpenangan Anda (atau yang serupa). Saya memberikannya waktu singkat 60 detik, jadi itu ada cukup lama untuk pengalihan terjadi.

if($has_error)
{
  set_transient( "acme_plugin_error_msg_$post_id", $error_msg, 60 );
}

Kemudian, cukup ambil pesan kesalahan itu di halaman berikutnya dan tampilkan. Saya juga menghapusnya agar tidak ditampilkan dua kali.

add_action('admin_notices', 'acme_plugin_show_messages');

function acme_plugin_show_messages()
{
  global $post;
  if ( false !== ( $msg = get_transient( "acme_plugin_error_msg_{$post->ID}" ) ) && $msg) {
    delete_transient( "acme_plugin_error_msg_{$post->ID}" );
    echo "<div id=\"acme-plugin-message\" class=\"error below-h2\"><p>$msg</p></div>";
  }
}

Karena admin_noticeskebakaran sebelum konten halaman utama dibuat, pemberitahuan tersebut bukan ke tempat pesan edit lainnya dikirim, jadi saya harus menggunakan jQuery ini untuk memindahkannya ke sana:

jQuery('h2').after(jQuery('#acme-plugin-message'));

Karena ID pos adalah bagian dari nama sementara, ini harus berfungsi di sebagian besar lingkungan multi-pengguna kecuali ketika beberapa pengguna secara bersamaan mengedit posting yang sama.

Joshua Coady
sumber
Bisakah Anda menguraikan "Karena ID pos adalah bagian dari nama sementara"? Saya membuat kelas untuk menangani pesan kesalahan menggunakan teknik ini, tetapi saya meminta konstruktor saya untuk meneruskan user_ID. Apakah API sementara menggunakan user_id saat hashing kunci? (Saya bertanya karena kodeks tersebut sepertinya tidak menyebutkan ini)
Gazillion
Tidak, tetapi Anda bisa menambahkannya secara manual. Dalam kode yang saya posting di atas, nama transient adalah acme_plugin_error_msg_POSTID. Anda bisa menambahkan ID pengguna seperti itu acme_plugin_error_msg_POSTID_USERID.
Joshua Coady
2

Saat save_postdijalankan, pos sudah tersimpan di database.

Melihat ke kode inti WordPress, lebih khusus pada fungsi wp-includes/post.php's update_post(), tidak ada cara built-in untuk mencegat permintaan sebelum disimpan di database.

Namun, kami dapat mengaitkan pre_post_updatedan menggunakan header()dan get_post_edit_link()mencegah agar pos tidak disimpan.

<?php

/**
*   Performs validation before saving/inserting custom post type
*/
function custom_post_site_save($post_id, $post_data) {
    // If this is just a revision, don't do anything.
    if (wp_is_post_revision($post_id))
        return;

    if ($post_data['post_type'] == 'my_custom_post_type') {
        // Deny post titles with less than 5 characters
        if (strlen($post_data['post_title'] < 5)) {
            header('Location: '.get_edit_post_link($post_id, 'redirect'));
            exit;
        }
    }
}
add_action( 'pre_post_update', 'custom_post_site_save', 10, 2);

Jika Anda memberi tahu pengguna apa yang salah, lihat intisari ini: https://gist.github.com/Luc45/09f2f9d0c0e574c0285051b288a0f935

Lucas Bustamante
sumber
Terima kasih untuk ini, menangani validasi dengan sempurna, baik untuk penerbitan pertama kali atau memperbarui posting. Anda baru saja menyelamatkan saya banyak waktu dan usaha.
Zade
1

Mengapa Anda tidak memvalidasi bidang Anda dengan bantuan beberapa Javascript? Saya pikir ini akan menjadi pendekatan terbaik untuk ini.

Horttcore
sumber
Terima kasih untuk sarannya! Apa yang saya tinggalkan dari pertanyaan (demi kesederhanaan) adalah bahwa saya mencoba untuk menangani kesalahan unggahan file, jadi itu perlu sisi server. Terima kasih untuk sarannya!
MathSmath
memvalidasi javascript tidak mencegah dari beberapa serangan, validasi sisi server adalah satu-satunya yang aman. Selain itu, wordpress menawarkan beberapa alat yang bagus untuk memvalidasi data pengguna. Tapi Anda benar jika hanya memeriksa beberapa nilai sebelum mengirim data ke server, Anda dapat menghemat waktu di server rendah ^^
nderambure
1

Mencoba menggunakan skrip di atas, saya mengalami masalah aneh. Dua pesan ditampilkan di layar edit, setelah pembaruan posting. Satu menunjukkan keadaan konten dari penyimpanan sebelumnya dan satu lagi dari saat ini. Misalnya, jika saya menyimpan posting dengan benar dan kemudian membuat kesalahan, yang pertama adalah "kesalahan" dan yang kedua adalah "ok" - meskipun mereka dihasilkan dalam waktu yang sama. Jika saya mengubah skrip dan hanya menambahkan satu pesan (mis. "Kesalahan"), awali satu pembaruan dengan "kesalahan" dan setelah itu yang lain dengan pesan "ok", "kesalahan" tetap (ditampilkan untuk kedua kalinya). Saya harus menyimpan dengan "ok" sekali lagi untuk menghilangkannya. Saya benar-benar tidak tahu apa yang salah, saya sudah mengujinya di tiga server lokal yang berbeda dan ada masalah yang sama pada masing-masing dari mereka.

jlub
sumber
Saya melakukan beberapa tes lagi dari versi skrip kedua yang lebih sederhana yang telah saya sebutkan di atas dan tampaknya jika pesan "error" benar-benar ditambahkan ke array sesi, itu ditampilkan di layar edit. Jika tidak ada pesan (semuanya "ok") dan pesan sebelumnya salah, pesan itu muncul di layar. Apa yang aneh, itu dihasilkan pada saat menyimpan (tidak di-cache) - Saya telah memeriksanya menggunakan date () di badan pesan kesalahan. Saya benar-benar bingung sekarang.
jlub
Ok, kalau-kalau ada orang yang menarik rambut dari kepalanya - ternyata sistem revisi Wordpress adalah masalahnya (beberapa jenis bug mungkin?). Saya telah menonaktifkannya dan sekarang semuanya baik-baik saja.
0

Saya telah menulis sebuah plugin yang menambahkan penanganan kesalahan flash untuk layar edit posting dan mencegah posting diterbitkan sampai bidang yang diperlukan diisi:

https://github.com/interconnectit/required-fields

Ini memungkinkan Anda untuk membuat setiap kolom tulisan wajib, tetapi Anda dapat menggunakan API yang disediakannya untuk membuat setiap kolom khusus yang diperlukan juga dengan pesan kesalahan yang dapat disesuaikan dan fungsi validasi. Ini default untuk memeriksa apakah bidang kosong atau tidak.

sanchothefat
sumber
Jangan ragu untuk menambahkan masalah apa pun di github jika Anda menemukannya. Saya perlu mendokumentasikan API sedikit lebih baik juga karena ada beberapa filter tambahan yang dapat Anda gunakan.
sanchothefat