Como diseñador y desarrollador web que utiliza WordPress como framework, muchas veces necesitarás añadir información o contenidos adicionales a los Post Types de WordPress para conseguir almacenar información que, de forma nativa, sería imposible.

En la anterior entrada te traía un tutorial sobre Custom Post Types donde te explicaba la forma correcta de utilizar los tipos de entradas personalizados para sacar más provecho a WordPress.

En esta ocasión te traigo una pequeña ampliación (aunque nada tiene que ver con los custom post types) con lo que podrás crear fichas de productos o darle un vitaminado general a las entradas (sean personalizadas o no) de tu WordPress.

¿Qué es un metabox en WordPress?

Si no lo sabes, un metabox te permite añadir campos extra a la página de edición de las entradas (como dije antes, sean del tipo que sean). Con esto podrás guardar más información sobre un mismo tipo de contenido. El ejemplo que utilizaré en esta entrada, será el mismo que utilicé para explicarte los custom post types de la entrada anterior.

*Te refresco la memoria: habíamos creado un custom post type "Libros" con el que añadir fichas de libros a nuestro WordPress; en el siempre hipotético caso de que nuestra web fuese a tratar de libros. Esto nos permitiría tener el blog original de WordPress intacto y las fichas de los libros almacenadas en otro tipo de entrada.

¿Cómo añadimos Metaboxes?

Te podría dar la respuesta sencilla de "con un plugin", pero si lees de forma regular mi blog sabrás que evito la dependencia de plugins al máximo.

custom post type

En esta imagen vemos cómo se ve la página de edición de nuestro custom post type de libros. Vamos a añadir un metabox con algunos datos más.

Para añadir un metabox, tenemos que utilizar la función add_meta_box, que según la documentación oficial recibe la siguiente información:

add_meta_box( $id, $title, $callback, $page, $context, $priority, $callback_args );

Al desglosar los parámetros que recibe, entendemos que:

Tras la breve explicación, nuestra llamada en el functions.php quedará así:

function dariobf_metabox() {
	add_meta_box( 'informacion-libro', 'Datos adicionales del libro', 'dariobf_meta_box_content', 'libro', 'normal', 'high' );
}
add_action( 'add_meta_boxes', 'dariobf_metabox' );

Algo a resaltar es que, he metido la llamada a add_meta_box dentro de una función (dariobf_metabox) y la he enganchado al hook add_meta_boxes. Si no sabes qué es un hook y cómo funciona, te recomiendo esta entrada.

Ahora veremos una página de edición más similar a esto:

custom metabox

Sigue faltando algo, ¿verdad?

Añadir campos al metabox

Esto del metabox está muy bien, pero no hemos añadido nada útil hasta el momento, ¿Qué tal si añado unos cuantos campos que me permitan crear una ficha de producto?

¿Recuerdas que prometí explicarte el uso de $callback en el primer punto de este tutorial? Ahora voy a crear una función con ese mismo nombre, que será la encargada de mostrar el contenido de nuestro metabox.

function dariobf_meta_box_content( $post ) {
    ?>
    <p>Aquí pondremos todo el contenido de nuestro metabox<p>
    <?php
}
custom metabox

Añadir campos de texto (Input text) al metabox

Partiendo de la función anterior, puedo añadir campos de texto al metabox, adaptándola de la siguiente forma para, por ejemplo, recoger el ISBN del libro en cuestión:

function dariobf_meta_box_content( $post ) {
    ?>
    <p>
        <label for="info_libro_isbn">ISBN</label>
        <input type="text" name="info_libro_isbn" id="info_libro_isbn" value="" />
    </p>
    <?php
}
metabox

Ya tenemos un campo ISBN, pero... ¿Cómo y dónde guarda la información que introduzco en el input? Fácil, en la base de datos, este campo será un custom field de WordPress.

Cuando edite un libro (recuerda que nuestro ejemplo va sobre fichas de libros) quiero recuperar esta información, así que tendré que utilizar la función get_post_meta.

Voy a añadir unas variables al ejemplo anterior que recuperarán esta información de la base de datos cada vez que carguemos la página de edición del libro.

function dariobf_meta_box_content( $post ) {
    $values    = get_post_custom( $post->ID );
    $isbn      = isset( $values['info_libro_isbn'] ) ? esc_attr( $values['info_libro_isbn'][0] ) : '';
    ?>
    <p>
        <label for="info_libro_isbn">ISBN</label>
        <input type="text" name="info_libro_isbn" id="info_libro_isbn" value="<?php echo esc_html( $isbn ); ?>" />
    </p>
    <?php
}

Con este añadido lo que hago es recoger la información del libro actual en la variable $values y, valiéndome de esta, el valor del input ISBN (en este ejemplo) en la variable $isbn. Como ves, también insertamos ese contenido recogido en $isbn dentro del value del input, lo que mostrará el contenido recogido anteriormente en dicho input.

Añadir un selector desplegable (Select) al metabox

Por razones lógicas, en ocasiones necesitarás darle al editor de la página la posibilidad de seleccionar una opción entre varias, por lo que vamos a añadir a nuestra ficha de libro dos campo select para, por ejemplo, el tipo de tapa de encuadernación de libro (Rústica, pegada o cosida) y para el tipo de tapa (dura o blanda).

function dariobf_meta_box_content( $post ) {
    $values         = get_post_custom( $post->ID );
    $isbn           = isset( $values['info_libro_isbn'] ) ? esc_attr( $values['info_libro_isbn'][0] ) : '';
    $encuadernacion = isset( $values['info_libro_encuadernacion'] ) ? esc_attr( $values['info_libro_encuadernacion'][0] ) : '';
    $tapa           = isset( $values['info_libro_tapa'] ) ? esc_attr( $values['info_libro_tapa'][0] ) : '';
    ?>
    <p>
        <label for="info_libro_isbn">ISBN</label>
        <input type="text" name="info_libro_isbn" id="info_libro_isbn" value="<?php echo esc_html( $isbn ); ?>" />
    </p>
    <p>  
        <label for="info_libro_encuadernacion">Tipo de encuadernación</label>  
        <select name="info_libro_encuadernacion" id="info_libro_encuadernacion">  
            <option value="rustica" <?php selected( $encuadernacion, 'rustica' ); ?>>Rústica</option>  
            <option value="pegada" <?php selected( $encuadernacion, 'pegada' ); ?>>Pegada</option>
            <option value="cosida" <?php selected( $encuadernacion, 'cosida' ); ?>>Cosida</option>  
        </select>
    </p> 
    <p>  
        <label for="info_libro_tapa">Tipo de Tapa</label>  
        <select name="info_libro_tapa" id="info_libro_tapa">  
            <option value="dura" <?php selected( $tapa, 'dura' ); ?>>Dura</option>  
            <option value="blanda" <?php selected( $tapa, 'blanda' ); ?>>Blanda</option>  
        </select>  
    </p>
    <?php
}

La función va cogiendo volumen, vamos por partes.

custom metabox

¿Vas cogiendo la idea? Con este sistema podemos añadir tantos campos como queramos, del tipo que queramos... Ahí va otro ejemplo más:

Añadiendo checkbox al metabox

A continuación añadiré un campo checkbox, que me permitirá marcar si hay stock o no del libro en cuestión.

function dariobf_meta_box_content( $post ) {
    $values         = get_post_custom( $post->ID );
    $isbn           = isset( $values['info_libro_isbn'] ) ? esc_attr( $values['info_libro_isbn'][0] ) : '';
    $encuadernacion = isset( $values['info_libro_encuadernacion'] ) ? esc_attr( $values['info_libro_encuadernacion'][0] ) : '';
    $tapa           = isset( $values['info_libro_tapa'] ) ? esc_attr( $values['info_libro_tapa'][0] ) : '';
    $check          = isset( $values['info_libro_stock'] ) ? esc_attr( $values['info_libro_stock'][0] ) : '';
    ?>
    <p>
        <label for="info_libro_isbn">ISBN</label>
        <input type="text" name="info_libro_isbn" id="info_libro_isbn" value="<?php echo esc_html( $isbn ); ?>" />
    </p>
    <p>  
        <label for="info_libro_encuadernacion">Tipo de encuadernación</label>  
        <select name="info_libro_encuadernacion" id="info_libro_encuadernacion">  
            <option value="rustica" <?php selected( $encuadernacion, 'rustica' ); ?>>Rústica</option>  
            <option value="pegada" <?php selected( $encuadernacion, 'pegada' ); ?>>Pegada</option>
            <option value="cosida" <?php selected( $encuadernacion, 'cosida' ); ?>>Cosida</option>  
        </select>
    </p> 
    <p>  
        <label for="info_libro_tapa">Tipo de Tapa</label>  
        <select name="info_libro_tapa" id="info_libro_tapa">  
            <option value="dura" <?php selected( $tapa, 'dura' ); ?>>Dura</option>  
            <option value="blanda" <?php selected( $tapa, 'blanda' ); ?>>Blanda</option>  
        </select>  
    </p>
    <p> 
        <input type="checkbox" id="info_libro_stock" name="info_libro_stock" <?php checked( $check, 'on' ); ?> />  
        <label for="info_libro_stock">Libro disponible en Stock</label>  
    </p>
    <?php
}

Al igual que con el input y el select, hemos agregado una variable que recoge la información de la base de datos (llamada $check) y el propio checkbox.

Creo que la idea se ha entendido; si no es así vuelve al punto donde explico cómo introducir el input text y el select.

Guardando los datos

Hasta ahora, hemos creado la interfaz de usuario: un metabox con varios campos que añaden información adicional a la ficha de los libros.

A ese metabox le hemos dado forma con una función donde, además, hemos dejado listas unas cuantas variables que recogen esa información de la base de datos cada vez que decidamos editar la ficha de un libro.

Pero... ¿En qué momento hemos guardado los datos? ¿Funciona por arte de magia? La respuesta, tras leer el título de esta sección, es obviamente que no; no hemos guardado los datos en ningún sitio, por lo que nuestro metabox todavía no es funcional.

Para guardar los datos necesitamos una función, que vamos a enganchar con el hook de WordPress save_post.

No te voy a pedir que entiendas cómo funciona este proceso, pero sí quiero que sepas que eso se hace con la función add_action de WordPress:

add_action( 'save_post', 'dariobf_metabox_save' );

Aún no he programado la función dariobf_metabox_save, que será la encargada de guardar nuestros datos.

Esta función recibirá un argumento, el id del post que estamos editando, y se encargará, como digo, de guardar todos los datos de nuestro metabox en la base de datos.

El hook save_post ejecutará nuestra función dariobf_metabox_save siempre pulsemos el botón "Guardar borrador" o "Actualizar" (también "Publicar") en la página de edición.

Antes de guardar la información, necesito verificar tres cosas:

  1. Si la entrada se está autoguardando
  2. Verificar el valor nonce que hemos creado en la función dariobf_metabox_content
  3. Comprobar que el usuario actual puede realmente modificar este contenido.
function dariobf_metabox_save( $post_id ) {
    // Ignoramos los auto guardados.
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
        return;
    }

    // Si no está el nonce declarado antes o no podemos verificarlo no seguimos.
    if ( ! isset( $_POST['bf_metabox_nonce'] ) || ! wp_verify_nonce( $_POST['bf_metabox_nonce'], 'dariobf_metabox_nonce' ) ) {
        return;
    }

    // Si el usuario actual no puede editar entradas no debería estar aquí.
    if ( ! current_user_can( 'edit_post' ) ) {
        return;
    }
}

Y, por fin, viene la última parte: guardar los datos.

Como primera regla a la hora de poner cualquier información en una base de datos diría que jamás te fíes del usuario.

Incluso si ese usuario es tu hermano, hermana o padre. Es más, incluso si ese usuario eres tú mismo, nunca te fíes de lo que intentan introducir en tu base de datos.

Por esto, antes de guardar los datos vamos a comprobar que no hay nada malicioso en los datos.

Afortunadamente WordPress cuenta con sistemas que controlan esto por nosotros.

Ya hemos utilizado antes la función esc_attr(). Esta función codifica las comillas simples y dobles así como los símbolos mayor qué y menor qué en HTML. Puedes leer más sobre esta función aquí.

Vamos a utilizar la función update_post_meta para guardar nuestros datos.

Esta función recibe tres argumentos: el ID del post, la "llave" (key) del meta y el valor.

function dariobf_metabox_save( $post_id ) {
    // Ignoramos los auto guardados.
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
        return;
    }

    // Si no está el nonce declarado antes o no podemos verificarlo no seguimos.
    if ( ! isset( $_POST['bf_metabox_nonce'] ) || ! wp_verify_nonce( $_POST['bf_metabox_nonce'], 'dariobf_metabox_nonce' ) ) {
        return;
    }

    // Si el usuario actual no puede editar entradas no debería estar aquí.
    if ( ! current_user_can( 'edit_post' ) ) {
        return;
    }

    // AHORA es cuando podemos guardar la información.

    // Nos aseguramos de que hay información que guardar.
    if ( isset( $_POST['info_libro_isbn'] ) ) {
        update_post_meta( $post_id, 'info_libro_isbn', wp_kses( $_POST['info_libro_isbn'], $allowed ) );
    }

    if ( isset( $_POST['info_libro_encuadernacion'] ) ) {
        update_post_meta( $post_id, 'info_libro_encuadernacion', esc_attr( $_POST['info_libro_encuadernacion'] ) );
    }

    if ( isset( $_POST['info_libro_tapa'] ) ) {
        update_post_meta( $post_id, 'info_libro_tapa', esc_attr( $_POST['info_libro_tapa'] ) );
    }

    // Así es como guardo yo los checkboxes; hay otros métodos, pero este es el mío.
    $check = isset( $_POST['info_libro_stock'] ) && $_POST['info_libro_stock'] ? 'on' : 'off';
    update_post_meta( $post_id, 'info_libro_stock', $check );
}
custom metaboxes

Con esto ya tenemos un metabox donde recoger nuestros campos personalizados de forma visual y fácil.

¿Cómo muestro los datos de un metabox en el Front-End?

Es sencillo, sólo tienes que utilizar get_post_meta o get_post_custom e imprimir la información en la plantilla correspondiente de tu tema.

Si te ha gustado no dudes en compartirlo con tus amigos y exponer todas tus dudas en los comentarios.

Puedes obtener más información sobre metaboxes en el códex.

Valora la entrada
(Votos: 0 Promedio: 0)