Özel alanlar doldurulmazsa yayının yayınlanmasını önleyin


17

Özel bir yazı türüm var EventBaşlangıç ​​ve bitiş tarihi / kez özel alanları (yazı düzenleme ekranında meta kutuları olarak) içeren var.

Bir Olayın tarihleri ​​doldurulmadan yayınlanamayacağından (veya zamanlanmadan) emin olmak istiyorum, çünkü bu Olay verilerini görüntüleyen şablonlarda sorunlara yol açacaktır (bunun yanında gerekli bir gerekliliktir!). Ancak, hazırlanırken geçerli bir tarih içermeyen Taslak etkinliklere sahip olmak istiyorum.

save_postDenetimi yapmayı düşünüyordum , ancak durum değişikliğinin olmasını nasıl önleyebilirim?

EDIT1: Bu post_meta kaydetmek için şimdi kullandığım kanca.

// 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: ve bu veritabanına kaydettikten sonra yazı verilerini kontrol etmek için kullanmaya çalışıyorum.

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

Bununla ilgili ana sorun, aslında başka bir soruda açıklanan bir sorundur : wp_update_post()bir save_postkanca içinde kullanmak sonsuz bir döngüyü tetikler.

EDIT3: Bunun wp_insert_post_datayerine çengelle yapmanın bir yolunu buldum save_post. Tek sorun şu anda post_statusgeri döndürülüyor, ancak şimdi "Yayınlandı gönder" yazan yanıltıcı bir mesaj görünüyor ( &message=6yönlendirilen URL'ye ekleyerek ), ancak durum Taslak olarak ayarlandı.

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

Yanıtlar:


16

M0r7if3r'in işaret ettiği gibi, bir postanın kanca kullanılarak yayınlanmasını engellemenin bir yolu yoktur save_post, çünkü kancanın ateşlendiği zaman, yazı zaten kaydedilir. Bununla birlikte, aşağıdakiler, wp_insert_post_datasonsuz bir döngüye neden olmadan ve kullanmadan durumu geri almanıza izin verecektir .

Aşağıdakiler test edilmemiştir, ancak çalışması gerekir.

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

Kontrol etmedim, ancak koda bakarak, geri bildirim mesajı yayının yayınlandığını gösteren yanlış mesajı gösterecektir. Bunun nedeni, WordPress'in bizi bir URL'ye yönlendirmesidir.message değişkenin şimdi yanlış .

Değiştirmek için redirect_post_locationfiltreyi kullanabiliriz :

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

Yukarıdaki yönlendirme filtresini özetlemek için: Bir yayın yayınlanacak şekilde ayarlanmışsa, ancak yine de bir taslaksa, mesajı buna göre değiştiririz (ki message=10). Yine, bu test edilmemiştir, ancak çalışması gerekir. Kodeksiadd_query_arg bir değişken zaten ayarlandığında, işlevin onun yerini aldığını gösterir (ama dediğim gibi, bunu test etmedim).


Kayıplar dışında; add_query_arg satırınızda, bu redirect_post_location filtre hile tam olarak ihtiyacım olan şey. Teşekkürler!
MadtownLems

@MadtownLems sabit :)
Stephen Harris

9

Tamam, bu nihayet bunu nasıl sona erdi: kontrol, bu cevap esinlenerek ve StackOverflow üzerinde sordum bir sorudan akıllı bir ipucu kullanarak bir PHP işlevine Ajax çağrısı . Önemlisi, sadece yayınlamak istediğimiz zaman kontrolün yapıldığından emin olurum, böylece bir Taslak her zaman kontrolsüz kaydedilebilir. Bu aslında önlenmesi daha kolay bir çözüm oldu yayınlanmasını için . Başka birine yardımcı olabilir, bu yüzden buraya yazdım.

İlk olarak, gerekli Javascript'i ekleyin:

//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
}
}

Ardından, denetimi işleyen işlev:

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

trueHer şey yolundaysa bu işlev geri döner ve gönderiyi normal kanal tarafından yayınlamak için formu gönderir. Aksi takdirde, işlev olarak gösterilen bir hata iletisi döndürür alert()ve form gönderilmez.


Aynı yaklaşımı izledim ve doğrulama işlevi doğru döndüğünde yazının "Yayınla" yerine "Taslak" olarak kaydedilmesini sağladım. Bunu nasıl düzelteceğinizden emin değilim !!! <br/> Ayrıca ajax çağrısı sırasında bir textarea alanı (örneğin post_content, başka bir metin alanı özel alanı) için veri almıyor musunuz?
Mahmudur

1
Bu çözümü biraz farklı bir şekilde uyguladım: her şeyden önce javascript'te aşağıdaki kodu başarı durumunda kullandım: delayed_autosave(); //get data from textarea/tinymce field jQuery('#publish').data("valid", true).trigger('click'); //publish postÇok teşekkürler.
Mahmudur

3

Bu konuda en iyi yolun, eğer durum değiştiğinde GERİ DÖNÜŞTÜRMEK gibi durum değişikliğinin olmasını önlemek için olmadığını düşünüyorum. Örneğin: save_postGerçekten yüksek bir önceliğe sahip (kanca, çok geç, yani meta eklentinizi yaptıktan sonra ateş edecek), sonrapost_status kaydedilen postayı beklemede (veya taslak veya (ölçütlerinizi karşılamıyorsa).

Alternatif bir strateji wp_insert_post_data, post_status'u doğrudan ayarlamak için bağlanmak olacaktır. Bu yöntemin dezavantajı, endişelendiğim kadarıyla, postmeta'yı henüz veritabanına eklememiş olmanızdır, bu nedenle kontrollerinizi yapmak için yerinde vb. veri tabanına ... performans veya kod olarak çok fazla yük haline gelebilir.


Şu anda save_postmetabox meta alanları kaydetmek için öncelik 1 ile kanca ; o zaman teklif ettiğiniz şey save_post, öncelikli olarak ikinci bir kancaya sahip olmak , diyelim ki 99 Bu bütünlüğü garanti eder mi? Herhangi bir nedenle ilk kanca tetiklenirse, meta veriler eklenir ve yayın yayınlanır, ancak ikinci kanca açılmazsa, geçersiz alanlarla sonuçlanırsanız ne olur?
englebip

İlk kancanın ateşleyeceği bir durum düşünemiyorum ama ikincisinin değil ... buna neden olabilecek bir senaryo düşünüyorsunuz? Bu konuda endişeleniyorsanız, meta meta ekleyebilir, meta meta gönderebilir ve ardından post_statusisterseniz tek bir çağrıda çalışan tek bir işlevdeki tümünü güncelleyebilirsiniz .
mor7ifer

Kodumu sorumu düzenleme olarak yayınladım; Ben ikinci bir kanca kullanmaya çalıştım save_postama bu sonsuz bir döngü tetikler.
englebip

Sorununuz, oluşturulan yayını kontrol etmeniz gerektiğidir. Yani if( get_post_status( $post_id ) == 'publish' )sen verileri yeniden tanımlanması olacaktır, çünkü kullanıyor istediğini $wpdb->postsde değil, veri $_POST[].
mor7ifer

0

En iyi yöntem JAVASCRIPT olabilir:

<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

Üzgünüm sana doğru bir cevap veremem ama son zamanlarda benzer bir şey yapmayı hatırlıyorum sadece tam olarak nasıl hatırlayamıyorum. Sanırım belki de bu konuda yaptım - varsayılan bir değer olduğum gibi bir şey ve kişi bunu değiştirmemişse bunu bir if ifadesinde aldım -> if(category==default category) {echo "You didn't pick a category!"; return them to the post creation page; }üzgünüm bu düz bir cevap değil ama umut biraz yardımcı olur.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.