如果元数据字段无效,则不要发布自定义帖子类型的帖子


12

我有一个名为的自定义帖子类型(CPT)event。我有一个带有几个字段的类型的元框。我想在发布事件之前验证一些字段。例如,如果未指定事件的日期,则我想显示一条提示性的错误消息,请保存该事件以供将来编辑,但禁止发布该事件。没有所有必要信息的CPT帖子的“待处理”状态是否是正确的处理方式?

进行CPT字段验证并阻止发布帖子的最佳做法是什么,但是将其保存以备将来编辑。

非常感谢,达莎


轻柔地提醒您此问题仍然需要接受的答案。;;)如果两个答案都不能解决您的问题,请考虑使用附加注释详细说明尚未解决的问题(或在可能的情况下需要帮助的地方)来更新您的问题。
t31os 2011年

Answers:


14

您可以停止将帖子与所有较小的JQuery hack一起保存,并在使用ajax保存在客户端或服务器端之前验证字段:

首先,我们添加JavaScript以捕获submit / publish事件,并在实际提交之前使用它来提交我们自己的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功能,以仅针对您的帖子类型进行验证,以增加针对您的帖子类型的功能,并在客户端进行验证,但我更喜欢在服务器端进行验证。


没有服务器端的方法可以做到这一点?
杰夫

1
这是服务器端的方法。
Bainternet 2014年

1
也许我误会了一些东西。看起来您只是在使用PHP来呈现进行验证的JavaScript。那不是服务器端验证。我不太了解如何pre_submit_validation配合
Jeff

第一个my_publish_admin_hook块确实拦截了客户端的提交后提交-但随后对pre_submit_validation执行服务器端验证的服务器(在中的pre-official-submit )进行了AJAX调用。
emc 2015年

1
即使使用AJAX进行验证,这仍然是客户端验证。客户端必须首先运行JavaScript才能进行任何验证。但是...我仍然发现此答案对于提交前验证很有用。谢谢!
cr0ybot

7

该方法有两个步骤:第一,用于保存自定义metabox字段数据的功能(已保存到save_post),第二,用于读取新的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);' ) );
        }
    }
}

对于多个metabox字段,只需添加更多完成标记并检索更多post_meta并进行更多测试。


1

您必须在ajax上检查/验证您的元字段值,即当用户单击“发布/更新”按钮时。在这里,我正在验证具有元字段“ product_number”的woocommerce产品的空值。

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();
}

0

只是想添加它,以使用Bainternet的解决方案来读取post变量,您将不得不$_POST['form_data']使用PHP parse_str函数来解析字符串(只是为了节省一些研究时间)。

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

然后,您可以使用来访问每个变量$varname。例如,如果您有一个名为“ my_meta”的元字段,则可以这样访问它:

$vars = parse_str ( $_POST['form_data'] ) 
if ( $my_meta == "something" ) { // do something }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.