it-swarm.com.de

Verhindert, dass Posts veröffentlicht werden, wenn benutzerdefinierte Felder nicht ausgefüllt sind

Ich habe einen benutzerdefinierten Beitragstyp Event, der ein benutzerdefiniertes Start- und Enddatum uhrzeitfeld enthält (als Metaboxen im Bearbeitungsbildschirm des Beitrags).

Ich möchte sicherstellen, dass ein Event nicht veröffentlicht (oder geplant) werden kann, ohne dass die Daten ausgefüllt sind, da dies Probleme mit den Vorlagen zur Anzeige der Eventdaten verursacht (abgesehen davon, dass dies eine notwendige Voraussetzung ist!). Ich würde jedoch gerne Entwürfe für Veranstaltungen haben, die kein gültiges Datum enthalten, während sie in Vorbereitung sind.

Ich wollte save_post einbinden, um die Überprüfung durchzuführen, aber wie kann ich verhindern, dass der Status geändert wird?

EDIT1: Dies ist der Hook, mit dem ich jetzt das post_meta speichere.

// 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: und das ist es, was ich versuche, um die Post-Daten nach dem Speichern in der Datenbank zu überprüfen.

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

Das Hauptproblem dabei ist ein Problem, das tatsächlich in/- eine andere Frage beschrieben wurde: Die Verwendung von wp_update_post() in einem save_post-Hook löst eine Endlosschleife aus.

EDIT3: Ich habe mir einen Weg ausgedacht, dies zu tun, indem ich wp_insert_post_data anstelle von save_post angehängt habe. Das einzige Problem ist, dass jetzt der post_status zurückgesetzt wird, aber jetzt eine irreführende Meldung mit dem Titel "Post published" angezeigt wird (indem &message=6 zur umgeleiteten URL hinzugefügt wird), der Status jedoch auf "Draft" gesetzt wird.

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
englebip

Wie m0r7if3r betonte, gibt es keine Möglichkeit, das Veröffentlichen eines Posts mit dem Hook save_post zu verhindern, da der Post zum Zeitpunkt des Auslösens des Hooks bereits gespeichert ist. Mit dem folgenden Befehl können Sie den Status jedoch wiederherstellen, ohne wp_insert_post_data zu verwenden und ohne eine Endlosschleife auszulösen.

Folgendes wird nicht getestet, sollte aber funktionieren.

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

Ich habe nicht geprüft, aber im Code wird in der Feedback-Nachricht die falsche Meldung angezeigt, dass der Beitrag veröffentlicht wurde. Dies liegt daran, dass WordPress uns zu einer URL umleitet, bei der die Variable message jetzt falsch ist.

Um dies zu ändern, können wir den redirect_post_location-Filter verwenden:

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

Um den obigen Weiterleitungsfilter zusammenzufassen: Wenn ein Beitrag veröffentlicht werden soll, aber noch ein Entwurf ist, ändern wir die Nachricht entsprechend (das ist message=10). Auch dies ist ungetestet, sollte aber funktionieren. Der Codex von add_query_arg legt nahe, dass die Funktion eine bereits gesetzte Variable ersetzt (aber wie gesagt, ich habe dies nicht getestet).

14
Stephen Harris

Ich denke, dass der beste Weg, dies zu tun, nicht darin besteht, die Statusänderung so sehr zu verhindern, als vielmehr, sie rückgängig zu machen, wenn dies der Fall ist. Zum Beispiel: Sie binden save_post mit einer sehr hohen Priorität ein (so dass der Hook sehr spät ausgelöst wird, nämlich nachdem Sie Ihre Metaeinfügung durchgeführt haben), überprüfen dann den post_status des gerade gespeicherten Posts und aktualisieren ihn auf ausstehend (oder Entwurf oder was auch immer), wenn es nicht Ihren Kriterien entspricht.

Eine alternative Strategie wäre, wp_insert_post_data einzuhängen, um den post_status direkt zu setzen. Der Nachteil dieser Methode ist meines Erachtens, dass Sie das Postmeta noch nicht in die Datenbank eingefügt haben, sodass Sie es usw. vor Ort verarbeiten müssen, um Ihre Überprüfungen durchzuführen, und es dann erneut verarbeiten müssen, um es einzufügen es in die Datenbank ... was entweder in der Leistung oder im Code eine Menge Overhead werden könnte.

3
mor7ifer

Die beste Methode könnte JAVASCRIPT sein:

<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>
0
T.Todua