Validierung und Fehlerbehandlung beim Speichern benutzerdefinierter Felder hinzufügen?

27

Ich habe eine Funktion, die ein benutzerdefiniertes Feld für einen Beitragstyp definiert. Angenommen, das Feld ist "subhead".

Wenn der Beitrag gespeichert wird, möchte ich eine Überprüfung der Eingabe durchführen und bei Bedarf eine Fehlermeldung auf dem Bildschirm zum Bearbeiten des Beitrags anzeigen. So etwas wie:

// Handle post updating
function wpse_update_post_custom_values($post_id, $post) {

    // Do some checking...
    if($_POST['subhead'] != 'value i expect') {

        // Add an error here
        $errors->add('oops', 'There was an error.');

    }

    return $errors;

} 
add_action('save_post','wpse_update_post_custom_values',1,2);

Ich versuche, dies mit der Aktion save_post zu verknüpfen, aber ich kann nicht herausfinden, wie ich mit Fehlern umgehen soll. Es scheint, dass kein Fehlerobjekt an die Funktion übergeben wurde, und wenn ich mein eigenes WP_Error-Objekt erstelle und es zurückgebe, wird es von keinem der Mechanismen beachtet, die Fehler auf der Nachbearbeitungsseite ausspucken.

Ich habe derzeit eine On-Page-Fehlermeldung in meiner benutzerdefinierten Meta-Box, aber dies ist weniger als ideal - ich hätte lieber einen großen, roten Fehler oben, wie er normalerweise in WP angezeigt wird.

Irgendwelche Ideen?

AKTUALISIEREN:

Basierend auf der Antwort von @Denis habe ich ein paar verschiedene Dinge ausprobiert. Das Speichern von Fehlern als global hat nicht funktioniert, da Wordpress während des Prozesses save_post eine Umleitung durchführt, die das globale Element beendet, bevor Sie es anzeigen können.

Am Ende habe ich sie in einem Metafeld gespeichert. Das Problem dabei ist, dass Sie sie löschen müssen oder sie nicht verschwinden, wenn Sie zu einer anderen Seite navigieren. Deshalb musste ich dem admin_footer eine weitere Funktion hinzufügen, die nur die Fehler löscht.

Ich hätte nicht erwartet, dass die Fehlerbehandlung für etwas so Häufiges (Aktualisieren von Posts) so umständlich wäre. Fehlt mir etwas Offensichtliches oder ist dies der beste Ansatz?

// Handle post updating
function wpse_5102_update_post_custom_values($post_id, $post) {

    // To keep the errors in
    $errors = false;

    // Do some validation...
    if($_POST['subhead'] != 'value i expect') {

        // Add an error here
        $errors .= 'whoops...there was an error.';

    }

    update_option('my_admin_errors', $errors);

    return;

} 
add_action('save_post','wpse_5102_update_post_custom_values',1,2);


// Display any errors
function wpse_5102_admin_notice_handler() {

    $errors = get_option('my_admin_errors');

    if($errors) {

        echo '<div class="error"><p>' . $errors . '</p></div>';

    }   

}
add_action( 'admin_notices', 'wpse_5102_admin_notice_handler' );


// Clear any errors
function wpse_5102__clear_errors() {

    update_option('my_admin_errors', false);

}
add_action( 'admin_footer', 'wpse_5102_clear_errors' );
MathSmath
quelle
Gute Frage. Ich denke, Sie könnten den admin_footerHaken loswerden, wenn Sie die Fehler am Ende Ihrer Benachrichtigungsfunktion beseitigen. Vereinfacht die Dinge nur ein bisschen.
Geert
Wie gehen Sie mit dem erneuten Ausfüllen der Formularfelder um (mit den möglicherweise ungültigen Daten)?
Geert
Ich habe eine grundlegende Frage. In welcher Wordpress-PHP-Datei ist das?
@ Karen Dies wäre in einer benutzerdefinierten Plugin-Datei oder in Ihrer functions.php.
MathSmath
Möglicherweise fehlt mir etwas Offensichtliches, aber wäre es etwas effizienter, update_option('my_admin_errors', false);unmittelbar nach der if-Anweisung am Ende von auszuführen wpse_5102_admin_notice_handler()?
Andrew Odri

Antworten:

6

Speichern Sie Fehler in Ihrer Klasse oder als globales Element, möglicherweise als Transient oder Meta, und zeigen Sie sie in Administratorbenachrichtigungen zu POST-Anforderungen an. WP verfügt über keinen Flash-Message-Handler.

Denis de Bernardy
quelle
Danke, dass Sie mich in diese Richtung gelenkt haben! Am Ende habe ich ein Meta zum Speichern von Fehlern verwendet, weil ich Probleme hatte, es als global oder als Eigenschaft auszuführen. Ich aktualisiere gerade meine Antwort, um zu erklären, wie ich es mache. Bitte lassen Sie mich wissen, ob Sie so etwas vorschlagen oder ob es einen besseren Weg gibt, den ich nicht verstehe.
MathSmath
So etwas, ja. Vielleicht aber auch in einer Sitzungsvariablen speichern. Auf diese Weise können mehrere Autoren gleichzeitig Beiträge bearbeiten. :-) Außerdem glaube ich, dass es nicht möglich ist, in einer Option falsch zu speichern. Speichern Sie stattdessen eine leere Zeichenfolge.
Denis de Bernardy
6

Ich empfehle die Verwendung von Sitzungen, da dies bei gleichzeitiger Bearbeitung durch zwei Benutzer keine seltsamen Effekte hervorruft. Das mache ich also:

Sitzungen werden nicht von WordPress gestartet. Sie müssen also eine Sitzung in Ihrem Plugin, functions.php oder sogar wp-config.php starten:

if (!session_id())
  session_start();

Fügen Sie beim Speichern des Beitrags Fehler und Hinweise an die Sitzung an:

function my_save_post($post_id, $post) {
   if($something_went_wrong) {
     //Append error notice if something went wrong
     $_SESSION['my_admin_notices'] .= '<div class="error"><p>This or that went wrong</p></div>';
     return false; //might stop processing here
   }
   if($somthing_to_notice) {  //i.e. successful saving
     //Append notice if something went wrong
     $_SESSION['my_admin_notices'] .= '<div class="updated"><p>Post updated</p></div>';
   }

   return true;
} 
add_action('save_post','my_save_post');

Drucken Sie Hinweise und Fehler und bereinigen Sie dann die Nachrichten in der Sitzung:

function my_admin_notices(){
  if(!empty($_SESSION['my_admin_notices'])) print  $_SESSION['my_admin_notices'];
  unset ($_SESSION['my_admin_notices']);
}
add_action( 'admin_notices', 'my_admin_notices' );
Davidn
quelle
Fehlerbehebung für die Sitzungsversion: Beim ersten Verwenden der Sitzungsvariablen nicht verwenden. = nur = Wenn Sie das Debuggen
3
Ich mache das auch, aber wenn Sie ein Plugin für ein breites Publikum wie dieses veröffentlichen, werden die Leute Sie dafür hassen. Wordpress instanziiert keine Sitzungen, da es so konzipiert ist, dass es statusfrei ist und diese nicht benötigt. Einige seltsame Server-Setups können dies verhindern. Verwenden Sie die Transienten-API - codex.wordpress.org/Transients_API anstelle von Sitzungen, um die Kompatibilität zu gewährleisten. Ich dachte, es lohnt sich, einen Grund anzugeben, warum dies hier nicht getan werden sollte.
Pospi
@pospi dies scheint ähnliche Probleme zu haben wie die ursprüngliche Verwendung der Funktionen get_option und update_option. Also würde die Lösung darin bestehen, die ID des aktuellen Benutzers an den Schlüssel anzuhängen?
Gazillion
Ja das würde total klappen! Solange Sie etwas hinzufügen, um den Benutzer eindeutig zu identifizieren, vermeiden Sie, dass Nachrichten zwischen angemeldeten Benutzern
verwechselt
5

Basierend auf Pospi ‚s Vorschlag zur Verwendung Transienten , kam ich mit der Follow - up. Das einzige Problem ist, dass es keinen Haken gibt, um die Nachricht unter das zu setzenh2 Position anderer Nachrichten platziert werden kann. Daher musste ich einen jQuery-Hack durchführen, um sie dort abzurufen.

Speichern Sie zunächst die Fehlermeldung in Ihrem save_post(oder einem ähnlichen) Handler. Ich gebe es eine kurze Lebensdauer von 60 Sekunden, so ist es gerade lang genug für die Umleitung passieren.

if($has_error)
{
  set_transient( "acme_plugin_error_msg_$post_id", $error_msg, 60 );
}

Rufen Sie dann diese Fehlermeldung beim Laden der nächsten Seite ab und zeigen Sie sie an. Ich lösche es auch, damit es nicht zweimal angezeigt wird.

add_action('admin_notices', 'acme_plugin_show_messages');

function acme_plugin_show_messages()
{
  global $post;
  if ( false !== ( $msg = get_transient( "acme_plugin_error_msg_{$post->ID}" ) ) && $msg) {
    delete_transient( "acme_plugin_error_msg_{$post->ID}" );
    echo "<div id=\"acme-plugin-message\" class=\"error below-h2\"><p>$msg</p></div>";
  }
}

Da es admin_noticesvor dem Generieren des primären Seiteninhalts zu Bränden kommt, befindet sich der Hinweis nicht dort, wo die anderen Nachbearbeitungsnachrichten abgelegt werden. Daher musste ich diese jQuery verwenden, um sie dorthin zu verschieben:

jQuery('h2').after(jQuery('#acme-plugin-message'));

Da die Beitrags-ID Teil des vorübergehenden Namens ist, sollte dies in den meisten Mehrbenutzerumgebungen funktionieren, es sei denn, mehrere Benutzer bearbeiten gleichzeitig denselben Beitrag.

Joshua Coady
quelle
Könnten Sie näher auf "Da die Post-ID Teil des vorübergehenden Namens ist" eingehen? Ich habe eine Klasse erstellt, um Fehlermeldungen mit dieser Technik zu behandeln, aber mein Konstruktor muss eine user_ID übergeben. Verwendet die transiente API die user_id beim Hashing des Schlüssels? (Ich frage, weil der Kodex dies nicht zu erwähnen scheint)
Gazillion
Nein, aber Sie können es manuell hinzufügen. In dem Code, den ich oben gepostet habe, ist der Name des Transienten acme_plugin_error_msg_POSTID. Sie können dem einfach eine Benutzer-ID hinzufügen acme_plugin_error_msg_POSTID_USERID.
Joshua Coady
2

Wenn save_postläuft, hat er bereits den Posten auf der Datenbank gespeichert.

Ein Blick in Wordpress Kern - Code, genauer gesagt an dem wp-includes/post.php‚s - update_post()Funktion, wird es keine integrierte Möglichkeit , eine Anfrage an abfangen , bevor sie in der Datenbank gespeichert wird.

Wir können jedoch einbinden pre_post_updateund verwenden header()und get_post_edit_link()verhindern, dass der Beitrag gespeichert wird.

<?php

/**
*   Performs validation before saving/inserting custom post type
*/
function custom_post_site_save($post_id, $post_data) {
    // If this is just a revision, don't do anything.
    if (wp_is_post_revision($post_id))
        return;

    if ($post_data['post_type'] == 'my_custom_post_type') {
        // Deny post titles with less than 5 characters
        if (strlen($post_data['post_title'] < 5)) {
            header('Location: '.get_edit_post_link($post_id, 'redirect'));
            exit;
        }
    }
}
add_action( 'pre_post_update', 'custom_post_site_save', 10, 2);

Wenn Sie den Benutzer darüber informieren möchten, dass ein Fehler aufgetreten ist, überprüfen Sie die folgende Liste: https://gist.github.com/Luc45/09f2f9d0c0e574c0285051b288a0f935

Lucas Bustamante
quelle
Vielen Dank, dass Sie die Validierung perfekt handhaben, egal ob Sie zum ersten Mal veröffentlichen oder den Beitrag aktualisieren. Sie haben mir viel Zeit und Mühe gespart.
Zade
1

Warum validieren Sie Ihr Feld nicht mit Hilfe von Javascript? Ich denke, das wäre der beste Ansatz dafür.

Horttcore
quelle
Danke für den Vorschlag! Was ich (der Einfachheit halber) von der Frage ausgeschlossen habe, ist, dass ich versuche, Datei-Upload-Fehler zu behandeln, so dass es serverseitig sein muss. Vielen Dank für den Vorschlag!
MathSmath
Die Überprüfung von Javascript verhindert einige Angriffe nicht. Die serverseitige Überprüfung ist die einzig sichere. Darüber hinaus bietet WordPress einige gute Tools zur Validierung von Benutzerdaten. Aber Sie haben Recht, wenn Sie nur einige Werte überprüfen, bevor Sie Daten an den Server senden, können Sie im Low-Server-
Modus
1

Beim Versuch, das obige Skript zu verwenden, stieß ich auf ein seltsames Problem. Nach dem Post-Update werden auf dem Bearbeitungsbildschirm zwei Nachrichten angezeigt. Einer zeigt den Status des Inhalts aus dem vorherigen Speichern und ein anderer aus dem aktuellen. Wenn ich zum Beispiel den Beitrag richtig speichere und dann einen Fehler mache, ist der erste "Fehler" und der zweite "OK" - obwohl sie gleichzeitig generiert werden. Wenn ich das Skript ändere und nur eine Meldung anhänge (zB "error"), starte ich ein Update mit "error" und danach mit "ok", bleibt die Meldung "error" (wird zum zweiten Mal angezeigt). Ich muss noch einmal mit "ok" speichern, um es loszuwerden. Ich weiß wirklich nicht, was los ist, ich habe es auf drei verschiedenen lokalen Servern getestet und es gibt auf jedem das gleiche Problem.

jlub
quelle
Ich habe einige weitere Tests der einfacheren, zweiten Version des Skripts durchgeführt, die ich oben erwähnt habe, und es scheint, dass, wenn die Fehlermeldung wirklich an das Sitzungsarray angehängt wird, sie auf dem Bearbeitungsbildschirm angezeigt wird. Wenn keine Meldung angezeigt wird (alles ist in Ordnung) und die vorherige Meldung ein Fehler war, wird sie auf dem Bildschirm angezeigt. Was seltsam ist, es wird zum Zeitpunkt des Speicherns generiert (nicht zwischengespeichert) - ich habe es mit date () im Hauptteil der Fehlermeldung überprüft. Ich bin jetzt total verwirrt.
jlub
Ok, falls jemand anderes sich die Haare aus dem Kopf zieht - es stellte sich heraus, dass das Wordpress-Revisionssystem das Problem war (eine Art Fehler wahrscheinlich?). Ich habe es deaktiviert und jetzt ist alles in Ordnung.
0

Ich habe ein Plugin geschrieben, das eine Flash-Fehlerbehandlung für Post-Edit-Bildschirme hinzufügt und das Veröffentlichen von Posts verhindert, bis erforderliche Felder ausgefüllt sind:

https://github.com/interconnectit/required-fields

Sie können alle Post-Felder als obligatorisch festlegen, aber Sie können die von ihr bereitgestellte API verwenden, um auch alle benutzerdefinierten Felder mit einer anpassbaren Fehlermeldung und Validierungsfunktion zu erstellen. Standardmäßig wird überprüft, ob das Feld leer ist oder nicht.

sanchothefat
quelle
Zögern Sie nicht, irgendwelche Probleme auf Github hinzuzufügen, wenn Sie auf sie stoßen. Ich muss die API auch ein bisschen besser dokumentieren, da es einige zusätzliche Filter gibt, die Sie verwenden können.
Ranchothefat