Cómo validar campos personalizados en un tipo de post personalizado

28 ago 2012, 23:15:25
Vistas: 18.8K
Votos: 9

Escribí un plugin que crea un tipo de post personalizado con campos personalizados. Para evitar que los usuarios ingresen información incorrecta, ¿cómo puedo validar los datos?

Supuse que la función del hook save_post procesaría la validación de campos, pero no encuentro una manera directa de mostrar los errores al usuario.

¿Existe alguna función o característica incorporada en WordPress para esto? ¿Cuál es la técnica general para implementar validación de campos personalizados?

0
Todas las respuestas a la pregunta 5
9

Vas por buen camino. Pruebo los campos en la devolución de llamada save_post, y luego uso avisos de administración para mostrar errores al usuario cuando un campo falla en la validación. Aparecen en un cuadro resaltado en la parte superior de la página, igual que cualquier error o mensaje que WordPress genere por sí mismo.

Aquí tienes un ejemplo simple de cómo crear un aviso de administración:

function my_admin_notice()
{
    ?>

    <div class="updated">
       <p>Aenean eros ante, porta commodo lacinia.</p>
    </div>

    <?php
}
add_action( 'admin_notices', 'my_admin_notice' );

Eso no es muy práctico, sin embargo. En una situación como esta, realmente quieres una función a la que puedas pasar un mensaje. Algo como:

if( $pizza != 'warm' )
    $notices->enqueue( 'La pizza no está caliente', 'error' );

Así que puedes escribir esa función enqueue() tú mismo (junto con una función para imprimir los avisos), o puedes incluir una biblioteca como IDAdminNotices.

Aquí tienes un ejemplo de un plugin que escribí. Este utiliza funciones de encolado e impresión de avisos que están integradas en la clase misma, en lugar de incluir una biblioteca externa.

public function saveCustomFields( $postID )
{
    // ...

    if( filter_var( $_POST[ self::PREFIX . 'zIndex'], FILTER_VALIDATE_INT ) === FALSE )
    {
        update_post_meta( $post->ID, self::PREFIX . 'zIndex', 0 );
        $this->enqueueMessage( 'El orden de apilamiento debe ser un número entero.', 'error' );
    }   
    else
        update_post_meta( $post->ID, self::PREFIX . 'zIndex', $_POST[ self::PREFIX . 'zIndex'] );

    // ...
}
add_action( 'save_post',    array( $this, 'saveCustomFields' );
29 ago 2012 00:21:14
Comentarios

No me queda muy claro... ¿tu código de ejemplo requiere código de terceros o funcionará en WordPress tal cual está?

Force Flow Force Flow
29 ago 2012 03:52:44

He añadido más detalles a la respuesta.

Ian Dunn Ian Dunn
29 ago 2012 04:37:58

Esto solo parece funcionar cuando la página se carga por primera vez. Si se hace clic en el botón "Actualizar/Publicar", no se muestran notificaciones.

Force Flow Force Flow
30 ago 2012 19:32:08

Ambos enfoques me funcionan. ¿Puedes publicar un enlace al código completo?

Ian Dunn Ian Dunn
30 ago 2012 22:43:27

Código de ejemplo: http://pastebin.com/vTxv9cw1

Force Flow Force Flow
30 ago 2012 23:51:16

Creo que el problema es que estás usando una variable global en lugar de guardar los avisos en la base de datos. Los datos en variables no persisten entre solicitudes. Entonces, el aviso se agrega a $bh_errorMessages en la solicitud de guardado, luego WordPress redirige de vuelta a la pantalla de Editar Entrada (que es una nueva solicitud), y todas las variables se reinician. Revisa http://en.wikipedia.org/wiki/Post/Redirect/Get. Examina más de cerca IDAdminNotices y asegúrate de estar haciendo todo lo que hace.

Ian Dunn Ian Dunn
31 ago 2012 19:09:56

No tengo muy claro qué estás usando para permitir que las variables persistan entre solicitudes. ¿Es la inclusión de la variable $instance? ¿O es una de las declaraciones add_action? ¿O ambas? ¿Algo más?

Force Flow Force Flow
4 sept 2012 16:38:14

Vale, creo que lo entendí. La magia está en las funciones de WordPress add_option y get_option para almacenar y recuperar la variable, y el hook shutdown es útil para llamar a la función add_option solo una vez por sesión después de que todo esté hecho.

Force Flow Force Flow
4 sept 2012 17:40:38

Sí, exactamente eso :)

Ian Dunn Ian Dunn
4 sept 2012 21:48:10
Mostrar los 4 comentarios restantes
0

Escribí un pequeño plugin que no solo valida los campos de entrada en tipos de contenido personalizados, sino que también elimina el aviso predeterminado del administrador, sin el uso de Javascript.

Aquí hay parte del código

/ Filtros de validación

$title = $album->post_title;
if ( ! $title ) {
    $errors['title'] = "El título es obligatorio";
}

// si tenemos errores, configuremos algunos mensajes
if (! empty($errors)) {

    // debemos eliminar esta acción o se ejecutará en bucle para siempre
    remove_action('save_post', 'album_save_post');

    // guardar los errores como opción
    update_option('album_errors', $errors);

    // Cambiar el estado de la entrada de publicado a borrador
    $album->post_status = 'draft';

    // actualizar la entrada
    wp_update_post( $album );

    // debemos volver a agregar esta acción
    add_action('save_post', 'album_save_post');

    // admin_notice es creado por un $_GET['message'] con un número que WordPress usa para
    // mostrar el mensaje del administrador, así que agregaremos un filtro para reemplazar el mensaje predeterminado con una redirección
    add_filter( 'redirect_post_location', 'album_post_redirect_filter' );
}

Puedes ver el tutorial completo aquí

31 mar 2013 13:59:03
0

Cuando save_post se ejecuta, el post ya ha sido guardado en la base de datos.

Si estás usando ACF, tiene validación incorporada.

Sin embargo, si necesitas validar elementos fuera de ACF, como el post_title, las cosas se complican un poco.

Al revisar el código núcleo de WordPress, más específicamente la función update_post() en wp-includes/post.php, no hay una forma incorporada de interceptar una solicitud antes de que se guarde en la base de datos.

No obstante, podemos engancharnos a pre_post_update y usar header() junto con get_post_edit_link() para evitar que el post se guarde.

<?php

/**
*   Realiza validación personalizada en el tipo de post personalizado "Site"
*/
function custom_post_site_save($post_id, $post_data) {
    # Si esto es solo una revisión, no hacer nada.
    if (wp_is_post_revision($post_id))
        return;

    if ($post_data['post_type'] == 'site') {
        # En este ejemplo, mostraremos un error para títulos de post con menos de 5 caracteres
        if (strlen($post_data['post_title']) < 5) {
            # Añadir una notificación
            update_option('my_notifications', json_encode(array('error', 'El título del post no puede tener menos de 5 caracteres.')));
            # Y redirigir
            header('Location: '.get_edit_post_link($post_id, 'redirect'));
            exit;
        }
    }
}
add_action( 'pre_post_update', 'custom_post_site_save', 10, 2);

/**
*   Muestra notificaciones personalizadas en el panel de administración de WordPress
*/
function my_notification() {
    $notifications = get_option('my_notifications');

    if (!empty($notifications)) {
        $notifications = json_decode($notifications);
        #notifications[0] = (string) Tipo de notificación: error, updated o update-nag
        #notifications[1] = (string) Mensaje
        #notifications[2] = (boolean) ¿Es descartable?
        switch ($notifications[0]) {
            case 'error': # rojo
            case 'updated': # verde
            case 'update-nag': # ?
                $class = $notifications[0];
                break;
            default:
                # Por defecto, usa error por si acaso
                $class = 'error';
                break;
        }

        $is_dismissable = '';
        if (isset($notifications[2]) && $notifications[2] == true)
            $is_dismissable = 'is_dismissable';

        echo '<div class="'.$class.' notice '.$is_dismissable.'">';
           echo '<p>'.$notifications[1].'</p>';
        echo '</div>';

        # Reiniciar la notificación
        update_option('my_notifications', false);
    }
}
add_action( 'admin_notices', 'my_notification' );
30 jul 2018 01:24:03
1

Solo quiero añadir a la excelente respuesta de @Lucas Bustamante que el valor de los campos personalizados puede accederse a través del global $_POST.

Por lo tanto, la respuesta de @Lucas Bustamante también es válida si la validación se refiere a un campo personalizado. Por ejemplo:

<?php

/**
*   Realiza validación personalizada en el tipo de post personalizado "Site"
*/
function custom_post_site_save($post_id, $post_data) {
    # Si esto es solo una revisión, no hacer nada.
    if (wp_is_post_revision($post_id))
        return;

    if ($post_data['post_type'] == 'site') {
        # En este ejemplo, generaremos un error para códigos postales con menos de 5 caracteres
        if (strlen($_POST['zip_code']) < 5) {
            # Añadir una notificación
            update_option('my_notifications', json_encode(array('error', 'El código postal no puede tener menos de 5 caracteres.')));
            # Y redireccionar
            header('Location: '.get_edit_post_link($post_id, 'redirect'));
            exit;
        }
    }
}
add_action( 'pre_post_update', 'custom_post_site_save', 10, 2);

/**
*   Muestra notificaciones personalizadas en el panel de administración de WordPress
*/
function my_notification() {
    $notifications = get_option('my_notifications');

    if (!empty($notifications)) {
        $notifications = json_decode($notifications);
        #notifications[0] = (string) Tipo de notificación: error, updated o update-nag
        #notifications[1] = (string) Mensaje
        #notifications[2] = (boolean) ¿Es descartable?
        switch ($notifications[0]) {
            case 'error': # rojo
            case 'updated': # verde
            case 'update-nag': # ?
                $class = $notifications[0];
                break;
            default:
                # Por defecto usa error por si acaso
                $class = 'error';
                break;
        }

        $is_dismissable = '';
        if (isset($notifications[2]) && $notifications[2] == true)
            $is_dismissable = 'is_dismissable';

        echo '<div class="'.$class.' notice '.$is_dismissable.'">';
           echo '<p>'.$notifications[1].'</p>';
        echo '</div>';

        # Reiniciamos la notificación
        update_option('my_notifications', false);
    }
}
add_action( 'admin_notices', 'my_notification' );
23 nov 2019 00:22:31
Comentarios

La redirección no es la mejor opción ya que pierdes todos los datos ingresados por un solo campo.

Picard Picard
13 oct 2021 16:19:00
0

Puedes usar el filtro "wp_insert_post_data" para modificar o verificar datos antes de que sean insertados en la base de datos

add_filter( 'wp_insert_post_data', 'validate_posttypes' );
function wpb_custom_excerpt($data) {
    str_starts_with($data['post_title'],'wp')?$data['post_title']='wp'.$data['post_title']:null;
    return $data;
}
7 may 2021 17:20:26