Dodać sprawdzanie poprawności i obsługę błędów podczas zapisywania niestandardowych pól?


27

Mam funkcję, która definiuje niestandardowe pole typu posta. Powiedzmy, że pole to „subhead”.

Gdy post zostanie zapisany, chcę przeprowadzić weryfikację danych wejściowych i w razie potrzeby wyświetlić komunikat o błędzie na ekranie edycji postu. Coś jak:

// 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);

Próbuję podłączyć to do działania save_post, ale nie mogę wymyślić, jak radzić sobie z błędami. Wydaje się, że do funkcji nie został przekazany obiekt błędu, a jeśli utworzę własny WP_Error obj i zwrócę go, żaden mechanizm nie wyrzuca go na stronę po edycji.

Obecnie mam komunikat o błędzie na stronie w moim niestandardowym polu meta, ale jest to mniej niż idealne - wolałbym mieć duży, czerwony błąd, jak zwykle wyświetlany WP.

Jakieś pomysły?

AKTUALIZACJA:

Na podstawie odpowiedzi @Denis próbowałem kilku różnych rzeczy. Przechowywanie błędów jako globalne nie działało, ponieważ Wordpress dokonuje przekierowania podczas procesu save_post, który zabija globalny, zanim będzie można go wyświetlić.

W końcu przechowałem je w polu meta. Problem polega na tym, że musisz je wyczyścić, inaczej nie znikną one, gdy przejdziesz do innej strony, więc musiałem dodać kolejną funkcję dołączoną do admin_footer, która po prostu usuwa błędy.

Nie spodziewałbym się, że obsługa błędów w przypadku czegoś tak powszechnego (aktualizacja postów) byłaby tak niezręczna. Czy brakuje mi czegoś oczywistego, czy jest to najlepsze podejście?

// 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' );

Dobre pytanie. Myślę, że możesz pozbyć się admin_footerhaka, jeśli usuniesz błędy na końcu funkcji obsługi powiadomień. Upraszcza to trochę.
Geert

Jak sobie radzisz z ponownym wypełnianiem pól formularza (z możliwymi nieprawidłowymi danymi)?
Geert

Mam podstawowe pytanie. W czym jest plik php Wordpress?

@Karen To byłoby w niestandardowym pliku wtyczki lub w pliku functions.php.
MathSmath

Być może brakuje mi czegoś oczywistego, ale czy nieco bardziej wydajne byłoby uruchomienie update_option('my_admin_errors', false);natychmiast po instrukcji if na końcu wpse_5102_admin_notice_handler()?
Andrew Odri,

Odpowiedzi:


6

Przechowuj błędy w swojej klasie lub jako globalne, być może przejściowe lub meta, i wyświetlaj je w powiadomieniach administratora na żądanie POST. WP nie obsługuje żadnego programu obsługi wiadomości flash.


Dzięki za skierowanie mnie w tym kierunku! W końcu użyłem meta do przechowywania błędów, ponieważ miałem problemy z próbą zrobienia tego jako globalnego lub właściwości. Aktualizuję teraz swoją odpowiedź, aby wyjaśnić, jak to robię ... daj mi znać, czy to jest to, co sugerujesz, lub czy istnieje lepszy sposób, którego nie rozumiem.
MathSmath,

Tego rodzaju rzeczy, tak. Może jednak przechowuję ją w zmiennej sesji, po przemyśleniu. To, aby umożliwić wielu autorom edytowanie postów jednocześnie. :-) Ponadto uważam, że nie można zapisać wartości false w opcji. Zamiast tego przechowuj pusty ciąg.
Denis de Bernardy,

6

Sugeruję użycie sesji, ponieważ nie spowoduje to dziwnych efektów, gdy dwóch użytkowników edytuje w tym samym czasie. Oto co robię:

Sesje nie są uruchamiane przez wordpress. Musisz więc rozpocząć sesję we wtyczce, functions.php, a nawet wp-config.php:

if (!session_id())
  session_start();

Podczas zapisywania postu dołącz do sesji błędy i powiadomienia:

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

Wydrukuj powiadomienia i błędy, a następnie wyczyść wiadomości w sesji:

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

poprawka do wersji sesji: przy pierwszym użyciu zmiennej sesji nie używaj. = tylko = jeśli włączysz debugowanie, możesz sprawdzić, dlaczego ...

3
Robię to również, ale jeśli udostępnisz taką wtyczkę szerokiej publiczności, ludzie będą cię nienawidzić. Wordpress nie tworzy instancji sesji, ponieważ jest zaprojektowany tak, aby był bezstanowy i nie potrzebował ich, a niektóre dziwne konfiguracje serwerów go zepsują. Użyj przejściowego interfejsu API - codex.wordpress.org/Transients_API zamiast sesji, aby zachować zgodność. Pomyślałem, że warto zgłosić powód, dla którego nie warto tego tutaj robić.
pospi

@pospi wydaje się, że mają podobne problemy jak pierwotne użycie funkcji get_option i update_option. Więc wydaje mi się, że rozwiązaniem byłoby dodanie identyfikatora bieżącego użytkownika do klucza?
Gazillion

Tak, to by całkowicie zadziałało! Tak długo, jak dodasz coś w celu jednoznacznej identyfikacji użytkownika, unikniesz pomyłek między zalogowanymi użytkownikami (:
pospi

5

Na podstawie pospi „s sugestia do korzystania nieustalonych , wpadłem poniżej. Jedynym problemem jest to, że nie ma zaczepu, aby umieścić wiadomość podh2 którym trafiają inne wiadomości, więc musiałem zrobić hack jQuery, aby ją tam dostać.

Najpierw zapisz komunikat o błędzie obok swojego save_post(lub podobnego) modułu obsługi. Daję mu krótki czas życia 60 sekund, więc jest wystarczająco długi, aby nastąpiło przekierowanie.

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

Następnie po prostu pobierz ten komunikat o błędzie przy ładowaniu następnej strony i wyświetl go. Ja również go usuwam, aby nie wyświetlał się dwukrotnie.

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

Ponieważ admin_noticespożary są generowane przed wygenerowaniem zawartości strony głównej, powiadomienie nie jest tam, gdzie idą inne wiadomości po edycji, więc musiałem użyć tego jQuery, aby go tam przenieść:

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

Ponieważ identyfikator postu jest częścią przejściowej nazwy, powinien on działać w większości środowisk dla wielu użytkowników, z wyjątkiem sytuacji, gdy wielu użytkowników jednocześnie edytuje ten sam post.


Czy mógłbyś rozwinąć temat „Ponieważ identyfikator postu jest częścią przejściowej nazwy”? Utworzyłem klasę do obsługi komunikatów o błędach przy użyciu tej techniki, ale wymagam od mojego konstruktora podania identyfikatora użytkownika. Czy przejściowy interfejs API używa identyfikatora użytkownika podczas mieszania klucza? (Pytam, bo kodeks chyba o tym nie wspomina)
Gazillion

Nie, ale możesz dodać go ręcznie. W kodzie, który zamieściłem powyżej, nazwa przemijającego to acme_plugin_error_msg_POSTID. Możesz po prostu dodać do tego identyfikator użytkownika acme_plugin_error_msg_POSTID_USERID.
Joshua Coady

2

Po save_posturuchomieniu zapisał już post w bazie danych.

Patrząc w WordPress kodu rdzenia, bardziej specyficznie w wp-includes/post.php„s update_post()funkcji, nie ma wbudowanego sposób przechwycić żądania, zanim zostanie zapisany w bazie danych.

Możemy jednak zaczepić się pre_post_updatei użyć header()i get_post_edit_link()zapobiec zapisaniu posta.

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

Jeśli chcesz powiadomić użytkownika, co poszło źle, sprawdź tę treść: https://gist.github.com/Luc45/09f2f9d0c0e574c0285051b288a0f935


Dziękujemy za to, doskonale obsługuje sprawdzanie poprawności, bez względu na to, czy publikujesz po raz pierwszy, czy aktualizujesz post. Właśnie zaoszczędziłeś mi dużo czasu i wysiłku.
Zade

1

Dlaczego nie zweryfikujesz swojego pola przy pomocy Javascript? Myślę, że byłoby to najlepsze podejście do tego.


Dzieki za sugestie! To, co pominąłem (dla uproszczenia), to to, że próbuję poradzić sobie z błędami przesyłania plików, więc musi to być po stronie serwera. Dziękuję za sugestię!
MathSmath,

sprawdzanie poprawności javascript nie zapobiega niektórym atakom, sprawdzanie poprawności po stronie serwera jest jedynym bezpiecznym. Ponadto Wordpress oferuje kilka dobrych narzędzi do sprawdzania poprawności danych użytkownika. Ale masz rację, jeśli po prostu sprawdzi niektóre wartości przed wysłaniem danych do serwera, możesz zaoszczędzić trochę czasu na niskim serwerze ^^
nderambure

1

Próbując użyć powyższego skryptu, napotkałem dziwny problem. Dwie wiadomości są wyświetlane na ekranie edycji po aktualizacji. Jeden pokazuje stan zawartości z poprzedniego zapisu, a drugi z bieżącego. Na przykład, jeśli poprawnie zapiszę post, a następnie popełnię błąd, pierwszy to „błąd”, a drugi „ok” - chociaż są one generowane w tym samym czasie. Jeśli zmienię skrypt i dołączę tylko jedną wiadomość (np. „Błąd”), zainicjuj jedną aktualizację za pomocą „błędu”, a następnie kolejną za pomocą „ok”, komunikat „błąd” pozostanie (wyświetlany po raz drugi). Muszę jeszcze raz zapisać za pomocą „ok”, aby się go pozbyć. Naprawdę nie wiem, co jest nie tak, przetestowałem to na trzech różnych serwerach lokalnych i na każdym z nich występuje ten sam problem.


Zrobiłem jeszcze kilka testów prostszej, drugiej wersji skryptu, o której wspomniałem powyżej i wydaje się, że jeśli komunikat „błąd” jest naprawdę dołączony do tablicy sesji, jest wyświetlany na ekranie edycji. Jeśli nie ma komunikatu (wszystko jest „ok”), a poprzedni komunikat był błędny, pojawia się na ekranie. Co dziwne, jest generowany w czasie zapisywania (nie w pamięci podręcznej) - sprawdziłem to przy użyciu date () w treści komunikatu o błędzie. Jestem teraz całkowicie zdezorientowany.
Jlub

Ok, na wypadek, gdyby ktoś wyciągał włosy z jego głowy - okazało się, że problemem był system weryfikacji Wordpress (prawdopodobnie jakiś błąd?). Wyłączyłem to i teraz wszystko jest w porządku.

0

Napisałem wtyczkę, która dodaje obsługę błędów flash dla ekranów edycji postów i zapobiega publikowaniu postów, dopóki wymagane pola nie zostaną wypełnione:

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

Pozwala wprowadzić obowiązkowe dowolne pola pocztowe, ale można użyć interfejsu API, który udostępnia, aby ustawić dowolne wymagane pola niestandardowe za pomocą dostosowanego komunikatu o błędzie i funkcji sprawdzania poprawności. Domyślnie sprawdza, czy pole jest puste, czy nie.


Nie wahaj się dodawać żadnych problemów na github, jeśli się z nimi spotkasz. Muszę też trochę udokumentować interfejs API, ponieważ istnieje kilka dodatkowych filtrów, których można użyć.
sanchothefat
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.