사용자 정의 필드가 채워지지 않은 경우 게시물이 게시되지 않도록 방지


17

Event시작 및 종료 날짜 / 시간 사용자 정의 필드를 포함 하는 사용자 정의 게시물 유형 이 있습니다 (게시 편집 화면에서 메타 박스로).

날짜를 채우지 않고는 이벤트를 게시 (또는 예약) 할 수 없도록하고 싶습니다. 필요한 요구 사항 외에도 이벤트 데이터를 표시하는 템플릿에 문제가 발생할 수 있기 때문입니다. 그러나 준비 중에 유효한 날짜가 포함되지 않은 초안 이벤트를 가질 수 있기를 원합니다.

나는 접선의 생각 save_post점검을 수행하는,하지만 어떻게 내가 일어나는 상태 변화를 방지 할 수 있습니까?

EDIT1 : 이것은 post_meta를 저장하기 위해 지금 사용하고있는 후크입니다.

// Save the Metabox Data
function ep_eventposts_save_meta( $post_id, $post ) {

if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
    return;

if ( !isset( $_POST['ep_eventposts_nonce'] ) )
    return;

if ( !wp_verify_nonce( $_POST['ep_eventposts_nonce'], plugin_basename( __FILE__ ) ) )
    return;

// Is the user allowed to edit the post or page?
if ( !current_user_can( 'edit_post', $post->ID ) )
    return;

// OK, we're authenticated: we need to find and save the data
// We'll put it into an array to make it easier to loop though

//debug
//print_r($_POST);

$metabox_ids = array( '_start', '_end' );

foreach ($metabox_ids as $key ) {
    $events_meta[$key . '_date'] = $_POST[$key . '_date'];
    $events_meta[$key . '_time'] = $_POST[$key . '_time'];
    $events_meta[$key . '_timestamp'] = $events_meta[$key . '_date'] . ' ' . $events_meta[$key . '_time'];
}

$events_meta['_location'] = $_POST['_location'];

if (array_key_exists('_end_timestamp', $_POST))
    $events_meta['_all_day'] = $_POST['_all_day'];

// Add values of $events_meta as custom fields

foreach ( $events_meta as $key => $value ) { // Cycle through the $events_meta array!
    if ( $post->post_type == 'revision' ) return; // Don't store custom data twice
    $value = implode( ',', (array)$value ); // If $value is an array, make it a CSV (unlikely)
    if ( get_post_meta( $post->ID, $key, FALSE ) ) { // If the custom field already has a value
        update_post_meta( $post->ID, $key, $value );
    } else { // If the custom field doesn't have a value
        add_post_meta( $post->ID, $key, $value );
    }
    if ( !$value ) 
                delete_post_meta( $post->ID, $key ); // Delete if blank
}

}

add_action( 'save_post', 'ep_eventposts_save_meta', 1, 2 );

EDIT2 : 데이터베이스에 저장 한 후 게시물 데이터를 확인하는 데 사용하려고합니다.

add_action( 'save_post', 'ep_eventposts_check_meta', 99, 2 );
function ep_eventposts_check_meta( $post_id, $post ) {
//check that metadata is complete when a post is published
//print_r($_POST);

if ( $_POST['post_status'] == 'publish' ) {

    $custom = get_post_custom($post_id);

    //make sure both dates are filled
    if ( !array_key_exists('_start_timestamp', $custom ) || !array_key_exists('_end_timestamp', $custom )) {
        $post->post_status = 'draft';
        wp_update_post($post);

    }
    //make sure start < end
    elseif ( $custom['_start_timestamp'] > $custom['_end_timestamp'] ) {
        $post->post_status = 'draft';
        wp_update_post($post);
    }
    else {
        return;
    }
}
}

이것의 주요 문제는 실제로 다른 질문 에서 설명 된 문제입니다 wp_update_post(). save_post훅 내에서 사용 하면 무한 루프가 트리거됩니다.

EDIT3 :wp_insert_post_data 대신 에 후크하여 방법을 찾았습니다 save_post. 유일한 문제는 이제 post_status되돌려졌지만 이제 "게시 된 게시물"이라는 잘못된 메시지 &message=6가 리디렉션 된 URL 에 추가 되어 표시 되지만 상태는 초안으로 설정되어 있다는 것입니다.

add_filter( 'wp_insert_post_data', 'ep_eventposts_check_meta', 99, 2 );
function ep_eventposts_check_meta( $data, $postarr ) {
//check that metadata is complete when a post is published, otherwise revert to draft
if ( $data['post_type'] != 'event' ) {
    return $data;
}
if ( $postarr['post_status'] == 'publish' ) {
    $custom = get_post_custom($postarr['ID']);

    //make sure both dates are filled
    if ( !array_key_exists('_start_timestamp', $custom ) || !array_key_exists('_end_timestamp', $custom )) {
        $data['post_status'] = 'draft';
    }
    //make sure start < end
    elseif ( $custom['_start_timestamp'] > $custom['_end_timestamp'] ) {
        $data['post_status'] = 'draft';
    }
    //everything fine!
    else {
        return $data;
    }
}

return $data;
}

답변:


16

m0r7if3r이 지적했듯이 후크가 실행될 때까지 게시물이 이미 저장되어 있기 때문에 후크를 사용하여 게시물이 게시되는 것을 막을 방법이 없습니다 save_post. 그러나 다음을 사용 wp_insert_post_data하면 무한 루프를 사용 하거나 사용 하지 않고 상태를 되돌릴 수 있습니다 .

다음은 테스트되지 않았지만 작동해야합니다.

<?php
add_action('save_post', 'my_save_post');
function my_save_post($post_id) {
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
         return;

    if ( !isset( $_POST['ep_eventposts_nonce'] ) )
         return;

    if ( !wp_verify_nonce( $_POST['ep_eventposts_nonce'], plugin_basename( __FILE__ ) ) )
         return;

    // Is the user allowed to edit the post or page?
     if ( !current_user_can( 'edit_post', $post->ID ) )
         return;

   // Now perform checks to validate your data. 
   // Note custom fields (different from data in custom metaboxes!) 
   // will already have been saved.
    $prevent_publish= false;//Set to true if data was invalid.
    if ($prevent_publish) {
        // unhook this function to prevent indefinite loop
        remove_action('save_post', 'my_save_post');

        // update the post to change post status
        wp_update_post(array('ID' => $post_id, 'post_status' => 'draft'));

        // re-hook this function again
        add_action('save_post', 'my_save_post');
    }
}
?>

확인하지는 않았지만 코드를 보면 피드백 메시지에 게시물이 게시 된 잘못된 메시지가 표시됩니다. 이것은 WordPress가 message변수가 잘못된 URL로 리디렉션하기 때문 입니다.

이를 변경하기 위해 redirect_post_location필터를 사용할 수 있습니다 .

add_filter('redirect_post_location','my_redirect_location',10,2);
function my_redirect_location($location,$post_id){
    //If post was published...
    if (isset($_POST['publish'])){
        //obtain current post status
        $status = get_post_status( $post_id );

        //The post was 'published', but if it is still a draft, display draft message (10).
        if($status=='draft')
            $location = add_query_arg('message', 10, $location);
    }

    return $location;
}

위의 리디렉션 필터를 요약하려면 : 게시물이 게시되도록 설정되었지만 여전히 초안 인 경우 그에 따라 메시지 ()를 변경합니다 message=10. 다시 말하지만 이것은 테스트되지 않았지만 작동합니다. Codex는 add_query_arg변수가 이미 설정되어있을 때 함수가 변수를 대체한다고 제안합니다 (그러나 말한 것처럼 테스트하지 않았습니다).


누락 이외의; add_query_arg 줄 에서이 redirect_post_location 필터 트릭은 정확히 내가 필요한 것입니다. 감사!
MadtownLems

@MadtownLems 고정 :)
스티븐 해리스

9

좋아, 이것이 마침내 내가 한 일입니다 .Ajax는 PHP 함수에 대한 호출을 확인하고, 이 답변 에서 영감을 얻은 것으로, StackOverflow에 질문 한 영리한 팁을 사용합니다 . 중요하게, 나는 우리가 확인을 게시하고 싶을 때만 확인하지 않고 초안을 항상 저장할 수 있도록해야합니다. 결과적으로 실제로 게시물 게시를 방지 하는 더 쉬운 솔루션 이되었습니다. 다른 사람에게 도움이 될 수 있으므로 여기에 썼습니다.

먼저 필요한 Javascript를 추가하십시오.

//AJAX to validate event before publishing
//adapted from /wordpress/15546/dont-publish-custom-post-type-post-if-a-meta-data-field-isnt-valid
add_action('admin_enqueue_scripts-post.php', 'ep_load_jquery_js');   
add_action('admin_enqueue_scripts-post-new.php', 'ep_load_jquery_js');   
function ep_load_jquery_js(){
global $post;
if ( $post->post_type == 'event' ) {
    wp_enqueue_script('jquery');
}
}

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 == 'event' ){
    ?>
    <script language="javascript" type="text/javascript">
        jQuery(document).ready(function() {
            jQuery('#publish').click(function() {
                if(jQuery(this).data("valid")) {
                    return true;
                }
                var form_data = jQuery('#post').serializeArray();
                var data = {
                    action: 'ep_pre_submit_validation',
                    security: '<?php echo wp_create_nonce( 'pre_publish_validation' ); ?>',
                    form_data: jQuery.param(form_data),
                };
                jQuery.post(ajaxurl, data, function(response) {
                    if (response.indexOf('true') > -1 || response == true) {
                        jQuery("#post").data("valid", true).submit();
                    } else {
                        alert("Error: " + response);
                        jQuery("#post").data("valid", false);

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

그런 다음 검사를 처리하는 함수는 다음과 같습니다.

add_action('wp_ajax_ep_pre_submit_validation', 'ep_pre_submit_validation');
function ep_pre_submit_validation() {
//simple Security check
check_ajax_referer( 'pre_publish_validation', 'security' );

//convert the string of data received to an array
//from /wordpress//a/26536/10406
parse_str( $_POST['form_data'], $vars );

//check that are actually trying to publish a post
if ( $vars['post_status'] == 'publish' || 
    (isset( $vars['original_publish'] ) && 
     in_array( $vars['original_publish'], array('Publish', 'Schedule', 'Update') ) ) ) {
    if ( empty( $vars['_start_date'] ) || empty( $vars['_end_date'] ) ) {
        _e('Both Start and End date need to be filled');
        die();
    }
    //make sure start < end
    elseif ( $vars['_start_date'] > $vars['_end_date'] ) {
        _e('Start date cannot be after End date');
        die();
    }
    //check time is also inputted in case of a non-all-day event
    elseif ( !isset($vars['_all_day'] ) ) {
        if ( empty($vars['_start_time'] ) || empty( $vars['_end_time'] ) ) {
            _e('Both Start time and End time need to be specified if the event is not an all-day event');
            die();              
        }
        elseif ( strtotime( $vars['_start_date']. ' ' .$vars['_start_time'] ) > strtotime( $vars['_end_date']. ' ' .$vars['_end_time'] ) ) {
            _e('Start date/time cannot be after End date/time');
            die();
        }
    }
}

//everything ok, allow submission
echo 'true';
die();
}

이 함수는 true모든 것이 정상인지를 반환 하고 일반 채널에서 게시물을 게시하는 양식을 제출합니다. 그렇지 않으면 함수는로 표시되는 오류 메시지를 리턴하며 alert()양식이 제출되지 않습니다.


유효성 검사 함수가 true를 반환 할 때 동일한 접근 방식을 사용하여 게시물을 "게시"대신 "초안"으로 저장했습니다. 어떻게 해결 해야할지 모르겠습니다 !!! <br/> 아약스 호출 중에 텍스트 영역 필드 (예 : post_content, 다른 텍스트 영역 사용자 정의 필드)에 대한 데이터를 얻지 못합니까?
Mahmudur

1
이 솔루션을 조금 다르게 적용했습니다. 우선 성공할 경우 자바 스크립트에서 아래 코드를 사용했습니다. delayed_autosave(); //get data from textarea/tinymce field jQuery('#publish').data("valid", true).trigger('click'); //publish post많은 감사합니다.
Mahmudur

3

이 문제를 해결하는 가장 좋은 방법은 상태 변경이 발생하는 경우이를 방지하는 것만 큼 발생하는 것을 방지하는 것이 아니라고 생각합니다. 예를 들어 : save_post우선 순위가 높은 후크 를 사용하여 (즉, 메타 삽입을 수행 한 후 후크가 매우 늦게 시작되도록) post_status방금 저장된 게시물의 게시물을 확인한 후 보류 중 (또는 초안 또는 조건에 맞지 않으면)

다른 전략은 wp_insert_post_datapost_status를 직접 설정 하기 위해 연결 하는 것 입니다. 내가 염려하는 한이 방법의 단점은 아직 데이터베이스에 postmeta를 삽입하지 않았으므로 검사를 수행하기 위해 처리해야합니다. 그런 다음 다시 처리하여 삽입해야한다는 것입니다 성능이나 코드면에서 많은 오버 헤드가 될 수 있습니다.


나는 현재 save_post메타 박스에서 메타 필드를 저장하기 위해 우선 순위 1로 연결 하고 있습니다. 당신이 제안하는 것은 save_post우선 순위, 예를 들어 99 로 두 번째 후크를 갖는 것입니까? 이것이 무결성을 보장합니까? 어떤 이유로 첫 번째 후크가 발생하고 메타 데이터가 삽입되고 게시물이 게시되지만 두 번째 후크가 생성되지 않으면 잘못된 필드로 끝나는 경우 어떻게됩니까?
englebip February

첫 번째 후크가 발생하지만 두 번째 후크는 발생하지 않는 상황을 생각할 수 없습니다. 걱정되는 경우 포스트 메타를 삽입하고 포스트 메타를 확인한 다음 post_status원하는 경우 단일 호출에서 실행되는 하나의 함수 에서 모두 를 업데이트 할 수 있습니다.
mor7ifer

내 질문에 대한 편집으로 내 코드를 게시했습니다. 두 번째 후크를 사용하려고했지만 save_post무한 루프가 트리거됩니다.
englebip

문제는 생성 된 게시물을 확인해야한다는 것입니다. 그래서 if( get_post_status( $post_id ) == 'publish' )당신은 당신의 데이터를 다시 정의되기 때문에, 사용하는 것으로 원하는 것입니다 $wpdb->posts에서가 아닌 데이터 $_POST[].
mor7ifer

0

가장 좋은 방법은 JAVASCRIPT 일 수 있습니다.

<script type="text/javascript">
var field_id =  "My_field_div__ID";    // <----------------- CHANGE THIS

var SubmitButton = document.getElementById("save-post") || false;
var PublishButton = document.getElementById("publish")  || false; 
if (SubmitButton)   {SubmitButton.addEventListener("click", SubmCLICKED, false);}
if (PublishButton)  {PublishButton.addEventListener("click", SubmCLICKED, false);}
function SubmCLICKED(e){   
  var passed= false;
  if(!document.getElementById(field_id)) { alert("I cant find that field ID !!"); }
  else {
      var Enabled_Disabled= document.getElementById(field_id).value;
      if (Enabled_Disabled == "" ) { alert("Field is Empty");   }  else{passed=true;}
  }
  if (!passed) { e.preventDefault();  return false;  }
}
</script>

-1

나는 당신에게 똑바로 대답 할 수는 없지만 최근에 비슷한 것을하는 것을 기억합니다. 나는 정확히 어떻게 기억할 수 없습니다. 나는 아마도 어쩌면 그 방법에 대해 생각했을 것입니다-나는 그것이 기본값이었던 것과 같은 것입니다. 그리고 사람이 그것을 바꾸지 않았다면 나는 이것을 if 문에서 선택했습니다 .-> if(category==default category) {echo "You didn't pick a category!"; return them to the post creation page; }죄송합니다. 조금 도움이됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.