カスタムフィールドを保存するときに検証とエラー処理を追加しますか?


27

投稿タイプのカスタムフィールドを定義する関数があります。フィールドが「サブヘッド」であるとします。

投稿が保存されたら、入力に対して何らかの検証を行い、必要に応じて投稿編集画面にエラーメッセージを表示します。何かのようなもの:

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

これをsave_postアクションにフックしようとしていますが、エラーの処理方法がわかりません。関数に渡されたエラーオブジェクトは存在しないようで、独自のWP_Error objを作成してそれを返す場合、ポスト編集ページでエラーを吐き出すメカニズムによって尊重されません。

現在、カスタムメタボックス内にページ上のエラーメッセージがありますが、これは理想的とは言えません。WPが通常表示するような、大きくて赤くて上部にエラーがあります。

何か案は?

更新:

@Denisの回答に基づいて、いくつかの異なることを試しました。エラーをグローバルとして保存することは機能しませんでした。これは、Wordpressがsave_postプロセス中にリダイレクトを行うため、グローバルを表示する前に強制終了するためです。

私はそれらをメタフィールドに保存することになりました。これに伴う問題は、それらをクリアする必要があることです。そうしないと、別のページに移動しても消えないため、エラーをクリアするだけのadmin_footerに追加された別の関数を追加する必要がありました。

非常に一般的なもの(投稿の更新)のエラー処理がこれほど不格好になるとは思いませんでした。明らかな何かを見逃していますか、これが最良のアプローチですか?

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

良い質問。admin_footer通知ハンドラー関数の最後でエラーをクリアすると、フックを取り除くことができると思います。物事を少し簡素化します。
ヘルト

フォームフィールドの再入力(無効なデータの可能性あり)にどのように対処していますか?
ヘルト

基本的な質問があります。これはどのWordpressのphpファイルですか?

@Karenこれは、カスタムプラグインファイルまたはfunctions.phpにあります。
MathSmath

私は明らかな何かを見逃しているかもしれませんがupdate_option('my_admin_errors', false);、末尾のifステートメントの直後に実行する方がわずかに効率的wpse_5102_admin_notice_handler()でしょうか?
アンドリューオドリ

回答:


6

エラーをクラスまたはグローバルとして、一時的またはメタに保存し、POSTリクエストの管理通知に表示します。WPは、フラッシュメッセージハンドラーを備えていません。


この方向を教えてくれてありがとう!グローバルまたはプロパティとしてメタデータを使用しようとすると問題が発生したため、メタを使用してエラーを保存することになりました。私はそれをどうやってやっているのかを説明するために今すぐ答えを更新しています...これがあなたが提案している種類のものであるか、私が得ていないより良い方法があるかどうかを教えてください。
MathSmath

そういうことです ただし、考え直してセッション変数に保存することもできます。これは、複数の作成者が投稿を同時に編集できるようにするためです。:-)また、オプションにfalseを格納することは不可能だと思います。代わりに空の文字列を保存します。
デニスドバーナルディ

6

セッションを使用することをお勧めします。これは、2人のユーザーが同時に編集しても、奇妙な効果が生じないためです。だからこれは私がやっていることです:

セッションはワードプレスでは開始されません。したがって、プラグイン、functions.php、またはwp-config.phpでセッション開始する必要があります。

if (!session_id())
  session_start();

投稿を保存するときに、セッションにエラーと通知を追加します。

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

通知とエラーを出力してから、セッションのメッセージを消去します。

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

セッションバージョンの修正:セッション変数を初めて使用するときは、。= only =を使用しないでください。デバッグを有効にすると、理由を確認できます...

3
私もこれをやっていますが、そのような幅広い聴衆にプラグインをリリースすると、人々はそれを嫌うことになります。Wordpressは、ステートレスであり、それらを必要としないように設計されているため、セッションをインスタンス化しません。また、いくつかの奇妙なサーバー設定により、セッションが壊れます。セッションの代わりに一時API-codex.wordpress.org/Transients_APIを使用すると、互換性が維持されます。ここでこれを行わない理由をフラグする価値があると考えました。
ポスピ

@pospiには、get_optionおよびupdate_option関数の元の使用と同様の問題があるようです。だから、解決策は現在のユーザーのIDをキーに追加することだと思いますか?
ガジリオン

ええ、それは完全に機能します!ユーザーを一意に識別するために何かを追加する限り、ログインしているユーザー間でメッセージが混同されないようにします(:
-pospi

5

一時的なものを使用するというpospi提案に基づいて、私は次のことを思いつきました。唯一の問題は、メッセージを下に置くためのフックがないことですh2、他のメッセージが送信さ場所のため、そこに到達するためにjQueryハックを行う必要がありました。

まず、save_post(または同様の)ハンドラーでエラーメッセージを保存します。60秒という短い有効期間を指定しているため、リダイレクトが発生するのに十分な長さです。

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

次に、次のページの読み込み時にそのエラーメッセージを取得して表示します。また、2回表示されないように削除します。

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_notices、主ページコンテンツが生成される前に、他のポスト編集メッセージが行くところ私はそこにそれを移動するには、このjQueryのを使用していたので、火災、通知は、ありません:

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

投稿IDは一時的な名前の一部であるため、複数のユーザーが同じ投稿を同時に編集している場合を除き、これはほとんどのマルチユーザー環境で機能するはずです。


「投稿IDは一時的な名前の一部であるため」について詳しく説明してください。この手法を使用してエラーメッセージを処理するクラスを作成しましたが、コンストラクターにuser_IDを渡す必要があります。一時APIは、キーをハッシュするときにuser_idを使用しますか?(コーデックスではこれに言及していないようですのでお願いします)
-Gazillion

いいえ。ただし、手動で追加できます。上記のコードでは、トランジェントの名前はacme_plugin_error_msg_POSTIDです。のようなユーザーIDを追加できますacme_plugin_error_msg_POSTID_USERID
ジョシュアコーディ

2

ときにsave_post実行され、それが既にデータベース上のポストを救いました。

WordPressコアコード、より具体的にはwp-includes/post.phpupdate_post()関数を見ると、データベースに保存される前にリクエストをインターセプトする組み込みの方法はありません。

しかし、フックpre_post_updateを使用header()get_post_edit_link()て、投稿が保存されないようにすることができます。

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

問題をユーザーに通知するには、次の要点を確認してください:https : //gist.github.com/Luc45/09f2f9d0c0e574c0285051b288a0f935


ありがとう あなたは私に多大な時間と労力を節約しました。
ザード

1

Javascriptを使用してフィールドを検証しないのはなぜですか?これが最善のアプローチだと思います。


提案をありがとう!(簡単にするため)質問から除外したのは、ファイルアップロードエラーを処理しようとしているということです。そのため、サーバー側にする必要があります。提案をありがとう!
MathSmath

JavaScriptの検証は一部の攻撃を防止しません。サーバー側の検証が唯一の安全な検証です。さらに、wordpressはユーザーデータを検証するための優れたツールを提供します。ただし、データをサーバーに送信する前に値を確認するだけであれば、サーバーが低い場合でも時間を節約できます^^
nderambure

1

上記のスクリプトを使用しようとすると、奇妙な問題に遭遇しました。更新後、編集画面に2つのメッセージが表示されます。1つは以前の保存のコンテンツの状態を示し、もう1つは現在の保存の状態を示しています。たとえば、投稿を適切に保存してからエラーを作成すると、最初の投稿は「エラー」、2番目の投稿は「OK」になりますが、同時に生成されます。スクリプトを変更して1つのメッセージ(たとえば「エラー」)のみを追加した場合、「エラー」で1つの更新を開始し、その後「OK」、「エラー」メッセージで別の更新を開始します(2度目に表示されます)。もう一度「ok」で保存する必要があります。何が間違っているのか本当にわかりません。3つの異なるローカルサーバーでテストしましたが、それぞれに同じ問題があります。


上記のシンプルな2番目のバージョンのスクリプトをさらにテストしましたが、「エラー」メッセージがセッション配列に実際に追加されると、編集画面に表示されるようです。メッセージがなく(すべてが「OK」)、前のメッセージがエラーであった場合、画面に表示されます。奇妙なことに、保存時に生成されます(キャッシュされません)-エラーメッセージの本文でdate()を使用してチェックしました。私は今完全に混乱しています。
jlub

OK、他の誰かが彼の頭から髪を抜いている場合-Wordpressリビジョンシステムが問題であることが判明しました(おそらく何らかのバグ?)。私はそれを無効にしました、そして今、すべてがうまくいきます。

0

投稿編集画面のフラッシュエラー処理を追加し、必須フィールドに入力するまで投稿が公開されないようにするプラグインを作成しました。

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

投稿フィールドを必須にすることができますが、提供されているAPIを使用して、カスタマイズ可能なエラーメッセージと検証機能を備えた必要なカスタムフィールドも作成できます。デフォルトでは、フィールドが空かどうかをチェックします。


あなたがそれらに遭遇した場合、githubに問題を追加することをheしないでください。使用できる追加のフィルターがあるため、APIについても少し詳しく説明する必要があります。
サンチョテファ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.