Thêm xác nhận và xử lý lỗi khi lưu các trường tùy chỉnh?


27

Tôi có một chức năng xác định một trường tùy chỉnh trên một loại bài. Nói trường là "tiêu đề phụ".

Khi bài đăng được lưu, tôi muốn thực hiện một số xác nhận trên đầu vào và hiển thị thông báo lỗi trên màn hình chỉnh sửa bài đăng nếu cần. Cái gì đó như:

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

Tôi đang cố gắng thực hiện hành động này với hành động save_post, nhưng tôi không thể tìm ra cách xử lý lỗi. Dường như không có một đối tượng lỗi nào được truyền vào hàm và nếu tôi tạo WP_Error obj của riêng mình và trả lại nó, nó sẽ không được tôn trọng bởi bất kỳ cơ chế nào phát sinh lỗi trên trang chỉnh sửa bài đăng.

Tôi hiện đang có một thông báo lỗi trên trang bên trong hộp meta tùy chỉnh của mình, nhưng điều này không lý tưởng - tôi muốn có một lỗi lớn, màu đỏ, nổi bật như WP thường hiển thị.

Có ý kiến ​​gì không?

CẬP NHẬT:

Dựa trên câu trả lời của @Denis, tôi đã thử một vài thứ khác nhau. Lưu trữ các lỗi như toàn cầu không hoạt động, vì Wordpress thực hiện chuyển hướng trong quá trình save_post, nó sẽ giết chết toàn cầu trước khi bạn có thể hiển thị nó.

Tôi đã kết thúc việc lưu trữ chúng trong một trường meta. Vấn đề với điều này là bạn cần phải xóa chúng hoặc chúng sẽ không biến mất khi bạn điều hướng đến một trang khác, vì vậy tôi đã phải thêm một chức năng khác được đính kèm vào admin_footer để xóa các lỗi.

Tôi không mong đợi rằng việc xử lý lỗi cho một cái gì đó quá phổ biến (cập nhật bài viết) sẽ trở nên rắc rối như vậy. Tôi đang thiếu một cái gì đó rõ ràng hay đây là cách tiếp cận tốt nhất?

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

Câu hỏi hay. Tôi nghĩ rằng bạn có thể thoát khỏi admin_footerhook nếu bạn xóa các lỗi ở cuối chức năng xử lý thông báo của bạn. Đơn giản hóa mọi thứ chỉ một chút.
Geert

Làm thế nào bạn đối phó với việc lặp lại các trường biểu mẫu (với dữ liệu không hợp lệ có thể)?
Geert

Tôi có một câu hỏi cơ bản. Tệp phppress Wordpress này là gì?

@Karen Điều này sẽ có trong một tệp plugin tùy chỉnh hoặc trong tệp.php của bạn.
MathSmath

Tôi có thể đang thiếu một cái gì đó rõ ràng, nhưng nó sẽ hiệu quả hơn một chút để chạy update_option('my_admin_errors', false);ngay sau câu lệnh if ở cuối wpse_5102_admin_notice_handler()?
Andrew Odri

Câu trả lời:


6

Lưu trữ các lỗi trong lớp của bạn hoặc dưới dạng toàn cầu, có thể là tạm thời hoặc meta và hiển thị chúng trong thông báo của quản trị viên về các yêu cầu POST. WP không có tính năng xử lý tin nhắn flash.


Cảm ơn đã chỉ cho tôi theo hướng này! Tôi đã kết thúc việc sử dụng một meta để lưu trữ lỗi, bởi vì tôi gặp vấn đề khi cố gắng thực hiện nó như một tài sản toàn cầu hoặc tài sản. Tôi đang cập nhật câu trả lời của mình ngay bây giờ để giải thích cách tôi đang thực hiện ... vui lòng cho tôi biết nếu đây là loại điều bạn đang đề xuất hoặc nếu có cách nào tốt hơn mà tôi không nhận được.
MathSmath

Đó là điều, yeah. Có thể lưu trữ nó trong một biến phiên, trên những suy nghĩ thứ hai, mặc dù. Điều này, để cho phép nhiều tác giả chỉnh sửa bài viết cùng một lúc. :-) Ngoài ra, tôi tin rằng không thể lưu trữ sai trong một tùy chọn. Lưu trữ một chuỗi trống thay thế.
Denis de Bernardy

6

Tôi đề nghị sử dụng các phiên vì điều này sẽ không tạo ra hiệu ứng lạ khi hai người dùng chỉnh sửa cùng một lúc. Vì vậy, đây là những gì tôi làm:

Phiên không được bắt đầu bằng wordpress. Vì vậy, bạn cần bắt đầu một phiên trong plugin, tests.php hoặc thậm chí wp-config.php:

if (!session_id())
  session_start();

Khi lưu bài đăng, hãy thêm các lỗi và thông báo vào phiên:

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

In các thông báo và lỗi và sau đó xóa các tin nhắn trong phiên:

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

sửa lỗi cho phiên bản phiên: tại lần đầu tiên sử dụng biến phiên không sử dụng. = only = nếu bạn bật gỡ lỗi, bạn có thể kiểm tra lý do tại sao ...

3
Tôi cũng đã từng làm điều này, nhưng nếu bạn phát hành một plugin cho nhiều đối tượng như thế thì mọi người sẽ ghét bạn vì nó. Wordpress không khởi tạo phiên vì nó được thiết kế không trạng thái và không cần chúng, và một số thiết lập máy chủ kỳ lạ sẽ phá vỡ phiên. Sử dụng API tạm thời - codex.wordpress.org/Transrons_API thay vì phiên và bạn sẽ duy trì khả năng tương thích. Chỉ cần nghĩ rằng nó đáng để gắn cờ một lý do tại sao không làm điều này ở đây.
pospi

@pospi điều này dường như có các vấn đề tương tự như việc sử dụng ban đầu các hàm get_option và update_option. Vì vậy, tôi đoán giải pháp sẽ là nối ID người dùng hiện tại vào khóa?
Gazillion

Vâng, điều đó sẽ hoàn toàn làm việc! Vì vậy, miễn là bạn thêm một cái gì đó để xác định duy nhất người dùng, bạn sẽ tránh các tin nhắn bị lẫn lộn giữa những người dùng đã đăng nhập (:
pospi

5

Dựa trên đề xuất của pospi để sử dụng tạm thời , tôi đã đưa ra những điều sau đây. Vấn đề duy nhất là không có móc để đặt tin nhắn bên dưới nơi các tin nhắn khác đi, vì vậy tôi đã phải thực hiện một cuộc tấn công jQuery để có được nó ở đó.h2

Đầu tiên, lưu thông báo lỗi nối bộ save_postxử lý (hoặc tương tự) của bạn. Tôi cho nó thời gian tồn tại ngắn là 60 giây, vì vậy nó chỉ đủ dài để chuyển hướng xảy ra.

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

Sau đó, chỉ cần truy xuất thông báo lỗi đó trên tải trang tiếp theo và hiển thị nó. Tôi cũng xóa nó để nó không được hiển thị hai lần.

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>";
  }
}

admin_noticeskích hoạt trước khi nội dung trang chính được tạo, thông báo không phải là nơi các thông báo chỉnh sửa bài đăng khác đi, vì vậy tôi đã phải sử dụng jQuery này để di chuyển nó đến đó:

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

Vì ID bài đăng là một phần của tên tạm thời, nên nó sẽ hoạt động trong hầu hết các môi trường nhiều người dùng ngoại trừ khi nhiều người dùng đồng thời chỉnh sửa cùng một bài.


Bạn có thể nói rõ hơn về "Vì ID bài đăng là một phần của tên tạm thời" không? Tôi đã tạo một lớp để xử lý các thông báo lỗi bằng kỹ thuật này nhưng tôi yêu cầu hàm tạo của tôi vượt qua user_ID. API tạm thời có sử dụng user_id khi băm khóa không? (Tôi hỏi vì codex dường như không đề cập đến điều này)
Gazillion

Không, nhưng bạn có thể thêm nó bằng tay. Trong mã tôi đã đăng ở trên, tên của thoáng qua là acme_plugin_error_msg_POSTID. Bạn chỉ có thể thêm ID người dùng vào đó acme_plugin_error_msg_POSTID_USERID.
Joshua Coady

2

Khi save_postchạy, nó đã lưu bài đăng trên cơ sở dữ liệu.

Nhìn vào mã lõi WordPress, cụ thể hơn tại wp-includes/post.php's update_post()chức năng, không có built-in cách để đánh chặn một yêu cầu trước khi nó được lưu trên cơ sở dữ liệu.

Tuy nhiên, chúng tôi có thể móc pre_post_updatevà sử dụng header()get_post_edit_link()để ngăn bài đăng được lưu.

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

Nếu bạn thông báo cho người dùng những gì đã sai, hãy kiểm tra ý chính này: https://gist.github.com/Luc45/09f2f9d0c0e574c0285051b288a0f935


Cảm ơn bạn vì điều này, xử lý xác nhận hoàn hảo, cho dù xuất bản lần đầu tiên hoặc cập nhật bài viết. Bạn vừa tiết kiệm cho tôi rất nhiều thời gian và công sức.
Zade

1

Tại sao bạn không xác thực trường của mình với sự trợ giúp của một số Javascript? Tôi nghĩ rằng đây sẽ là cách tiếp cận tốt nhất cho việc này.


Cám ơn vì sự gợi ý! Điều tôi bỏ qua câu hỏi (vì đơn giản) là tôi đang cố xử lý các lỗi tải lên tệp, vì vậy nó cần phải ở phía máy chủ. Nhờ đề nghị mặc dù!
MathSmath

xác thực javascript không ngăn chặn một số cuộc tấn công, xác thực phía máy chủ là bảo mật duy nhất. Hơn nữa, wordpress cung cấp một số công cụ tốt để xác thực dữ liệu người dùng. Nhưng bạn đã đúng nếu chỉ kiểm tra một số giá trị trước khi gửi dữ liệu đến máy chủ, bạn có thể tiết kiệm thời gian trong máy chủ thấp ^^
nderambure

1

Cố gắng sử dụng đoạn script trên, tôi gặp phải một vấn đề lạ. Hai thông báo được hiển thị trên màn hình chỉnh sửa, sau khi cập nhật bài viết. Một là hiển thị trạng thái của nội dung từ lưu trước đó và một trạng thái khác từ hiện tại. Ví dụ: nếu tôi lưu bài đăng đúng cách và sau đó gây ra lỗi, thì cái đầu tiên là "lỗi" và cái thứ hai là "ok" - mặc dù chúng được tạo ra cùng một lúc. Nếu tôi thay đổi tập lệnh và chỉ thêm một thông báo (ví dụ: "lỗi"), hãy bắt đầu một bản cập nhật với "lỗi" và sau đó một bản cập nhật khác có thông báo "ok", "lỗi" (được hiển thị lần thứ hai). Tôi phải tiết kiệm với "ok" một lần nữa để thoát khỏi nó. Tôi thực sự không biết điều gì sai, tôi đã thử nghiệm nó trên ba máy chủ cục bộ khác nhau và có cùng một vấn đề trên mỗi máy chủ.


Tôi đã thực hiện thêm một số thử nghiệm về phiên bản kịch bản thứ hai đơn giản hơn mà tôi đã đề cập ở trên và dường như nếu thông báo "lỗi" thực sự được thêm vào mảng phiên, nó sẽ được hiển thị trên màn hình chỉnh sửa. Nếu không có tin nhắn (mọi thứ đều "ok") và tin nhắn trước đó bị lỗi, nó sẽ xuất hiện trên màn hình. Có gì lạ, nó được tạo vào thời điểm lưu (không được lưu trong bộ nhớ cache) - Tôi đã kiểm tra nó bằng ngày () trong phần thân thông báo lỗi. Bây giờ tôi hoàn toàn bối rối.
jlub

Ok, trong trường hợp có ai khác nhổ tóc ra khỏi đầu - hóa ra hệ thống sửa đổi Wordpress là vấn đề (có thể là một loại lỗi nào đó?). Tôi đã vô hiệu hóa nó và bây giờ mọi thứ đều ổn.

0

Tôi đã viết một plugin bổ sung xử lý lỗi flash cho màn hình chỉnh sửa bài đăng và ngăn bài đăng được xuất bản cho đến khi các trường bắt buộc được điền:

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

Nó cho phép bạn thực hiện bất kỳ trường bài đăng nào là bắt buộc nhưng bạn có thể sử dụng API mà nó cung cấp để thực hiện bất kỳ trường tùy chỉnh nào được yêu cầu với thông báo lỗi tùy chỉnh và chức năng xác thực. Nó mặc định để kiểm tra xem trường có trống hay không.


Đừng ngần ngại thêm bất kỳ vấn đề nào trên github nếu bạn gặp chúng. Tôi cần ghi lại API tốt hơn một chút vì có một số bộ lọc bổ trợ mà bạn có thể sử dụng.
sanchothefat
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.