web-dev-qa-db-ja.com

メタデータフィールドが無効な場合、カスタム投稿タイプの投稿を公開しない

eventというカスタム投稿タイプ(CPT)があります。いくつかのフィールドを持つタイプのメタボックスがあります。イベントを公開する前に、いくつかのフィールドを検証したいと思います。たとえば、イベントの日付が指定されていない場合、有益なエラーメッセージを表示し、将来の編集のためにイベントを保存しますが、そのイベントが公開されないようにします。必要な情報がすべて含まれていないCPT投稿の「保留」ステータスは、それを処理する正しい方法ですか?

CPTフィールドの検証を行い、投稿が公開されないようにするためのベストプラクティスですが、今後の編集のために保存してください。

ありがとう、ダーシャ

11
dashaluna

Ajaxを使用してクライアント側またはサーバー側に保存する前に、投稿がマイナーなJQueryハックと一緒にすべて保存されるのを防ぐことができます。

最初にJavaScriptを追加して送信/公開イベントをキャプチャし、それを使用して実際の送信の前に独自のajax関数を送信します。

 add_action('wp_print_scripts','my_publish_admin_hook');

function my_publish_admin_hook(){
if (is_admin()){
        ?>
        <script language="javascript" type="text/javascript">
            jQuery(document).ready(function() {
                jQuery('#post').submit(function() {

                    var form_data = jQuery('#post').serializeArray();
                    form_data = jQuery.param(form_data);
                    var data = {
                        action: 'my_pre_submit_validation',
                        security: '<?php echo wp_create_nonce( 'pre_publish_validation' ); ?>',
                        form_data: form_data
                    };
                    jQuery.post(ajaxurl, data, function(response) {
                        if (response.indexOf('True') > -1 || response.indexOf('true') > -1 || response === true ||  response) {
                            jQuery('#ajax-loading').hide();
                            jQuery('#publish').removeClass('button-primary-disabled');
                            return true;
                        }else{
                            alert("please correct the following errors: " + response);
                            jQuery('#ajax-loading').hide();
                            jQuery('#publish').removeClass('button-primary-disabled');
                            return false;
                        }
                    });
                    return false;
                });
            });
        </script>
        <?php
    }
}

それから実際の検証をするための関数を作成します。

add_action('wp_ajax_my_pre_submit_validation', 'pre_submit_validation');
function pre_submit_validation(){
    //simple Security check
    check_ajax_referer( 'pre_publish_validation', 'security' );

    //do your validation here
    //all of the form fields are in $_POST['form_data'] array
    //and return true to submit: echo 'true'; die();
    //or your error message: echo 'bal bla bla'; die();
}

ポストタイプのmy_publish_admin_hook関数に条件付きチェックを追加してクライアント側で検証することで、ポストタイプに対してのみ検証を行うように常に少し変更することができますが、サーバー側で検証することをお勧めします。

13
Bainternet

このメソッドには2つのステップがあります。1つはカスタムメタボックスフィールドデータを保存する関数(save_postにフック)、2つ目はその新しいpost_meta(先ほど保存したもの)を読み込み、それを検証して結果を変更する関数です。必要に応じて保存します(save_postにフックしましたが、最初のものの後に)。検証が失敗した場合、バリデーター関数は実際にpost_statusを "pending"に戻し、事実上投稿が公開されるのを防ぎます。

Save_post関数は頻繁に呼び出されるので、各関数はユーザーが公開することを意味する場合にのみ実行するチェックを持ち、カスタム投稿タイプ(mycustomtype)に対してのみ実行されます。

私は通常、自分の投稿が公開されなかった理由をユーザーに知らせるためのカスタム通知メッセージも追加しますが、ここに含めるのは少し複雑になります...

この正確なコードをテストしたことはありませんが、大規模なカスタム投稿タイプの設定で行ったことを単純化したものです。

add_action('save_post', 'save_my_fields', 10, 2);
add_action('save_post', 'completion_validator', 20, 2);

function save_my_fields($pid, $post) {
    // don't do on autosave or when new posts are first created
    if ( ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) || $post->post_status == 'auto-draft' ) return $pid;
    // abort if not my custom type
    if ( $post->post_type != 'mycustomtype' ) return $pid;

    // save post_meta with contents of custom field
    update_post_meta($pid, 'mymetafield', $_POST['mymetafield']);
}


function completion_validator($pid, $post) {
    // don't do on autosave or when new posts are first created
    if ( ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) || $post->post_status == 'auto-draft' ) return $pid;
    // abort if not my custom type
    if ( $post->post_type != 'mycustomtype' ) return $pid;

    // init completion marker (add more as needed)
    $meta_missing = false;

    // retrieve meta to be validated
    $mymeta = get_post_meta( $pid, 'mymetafield', true );
    // just checking it's not empty - you could do other tests...
    if ( empty( $mymeta ) ) {
        $meta_missing = true;
    }

    // on attempting to publish - check for completion and intervene if necessary
    if ( ( isset( $_POST['publish'] ) || isset( $_POST['save'] ) ) && $_POST['post_status'] == 'publish' ) {
        //  don't allow publishing while any of these are incomplete
        if ( $meta_missing ) {
            global $wpdb;
            $wpdb->update( $wpdb->posts, array( 'post_status' => 'pending' ), array( 'ID' => $pid ) );
            // filter the query URL to change the published message
            add_filter( 'redirect_post_location', create_function( '$location','return add_query_arg("message", "4", $location);' ) );
        }
    }
}

複数のメタボックスフィールドの場合は、補完マーカーを追加してpost_metaを取得し、テストを増やすだけです。

6
somatic

ajaxでメタフィールドの値を確認/検証する必要があります。つまり、ユーザーが[公開/更新]ボタンをクリックしたときです。ここでは、空の値に対してメタフィールド "product_number"を持つウーコマース商品を検証しています。

add_action('admin_head-post.php','ep_publish_admin_hook');
add_action('admin_head-post-new.php','ep_publish_admin_hook');

function ep_publish_admin_hook(){
    global $post;
    if ( is_admin() && $post->post_type == 'product' ){
        ?>
        <script language="javascript" type="text/javascript">
            (function($){
                jQuery(document).ready(function() {

                    jQuery('#publish').click(function() {
                        if(jQuery(this).data("valid")) {
                            return true;
                        }

                        //hide loading icon, return Publish button to normal
                        jQuery('#publishing-action .spinner').addClass('is-active');
                        jQuery('#publish').addClass('button-primary-disabled');
                        jQuery('#save-post').addClass('button-disabled');

                        var data = {
                            action: 'ep_pre_product_submit',
                            security: '<?php echo wp_create_nonce( "pre_publish_validation" ); ?>',
                            'product_number': jQuery('#acf-field-product_number').val()
                        };
                        jQuery.post(ajaxurl, data, function(response) {

                            jQuery('#publishing-action .spinner').removeClass('is-active');
                            if ( response.success ){
                                jQuery("#post").data("valid", true).submit();
                            } else {
                                alert("Error: " + response.data.message );
                                jQuery("#post").data( "valid", false );

                            }
                            //hide loading icon, return Publish button to normal
                            jQuery('#publish').removeClass('button-primary-disabled');
                            jQuery('#save-post').removeClass('button-disabled');
                        });
                        return false;
                    });
                });
            })(jQuery);
        </script>
        <?php
    }
}

その後、ajaxハンドラ関数を追加してください。

add_action('wp_ajax_ep_pre_product_submit', 'ep_pre_product_submit_func');
function ep_pre_product_submit_func() {
    //simple Security check
    check_ajax_referer( 'pre_publish_validation', 'security' );

    if ( empty( $_POST['product_number'] ) || empty( $_POST['file_attachment'] ) ) {
         $data = array(
            'message' => __('Please enter part number and specification document.'),
        );
        wp_send_json_error( $data );
    }
    wp_send_json_success();
}
1
Mohan Dere

Bainternetのソリューションを使ってpost変数を読むためにそれを追加したいのなら、PHP $_POST['form_data']関数を使ってparse_strの文字列をパースする必要があります(研究時間を節約するためだけに)。

$vars = parse_str( $_POST['form_data'] );

それから$varnameを使うだけで各変数にアクセスできます。たとえば、 "my_meta"というメタフィールドがある場合は、次のようにアクセスします。

$vars = parse_str ( $_POST['form_data'] ) 
if ( $my_meta == "something" ) { // do something }
0
Agus