Metaboxes en WordPress, cómo crearlos

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.

¡MANTENME INFORMADO!

¡Gracias por tu interés en estar informado del próximo lanzamiento de mis cursos! 😎

¡No hago spam! Lee la política de privacidad para tener más información.

41 comentarios en “Metaboxes en WordPress, cómo crearlos

    1. Es un proyecto propio que lanzaré próximamente. Lo verás en cuanto salga ;-)

      Ya sabes, mete un campo tipo text para recoger el autor :-P

      Esto tiene una pila posibilidades… jaja

  1. Buenísimo Diario. Muy completo, felicidades!
    Para los metabox siempre había utilizado el CMB (Custom Metaboxes and Fields) como framework, pero imagino que al final estás cargando mucho más código de lo necesario.

    Con lo que cuentas creo que se optimiza más si solo quieres un par de campos extras en un número pequeño de custom post types. Muy bueno repito, me lo guardo para el próximo proyecto!

    Saludos :-)

    1. Todo lo que sea evitarle cargas al servidor, o al propio visitante es mejor. Con esto controlas exactamente qué añades y da un control total.

      ¡Me alegro que te guste Ricardo! :-D

  2. Es muy interesante. Lo que me queda es investigar como realizar las búsquedas y ordenar a partir de los metacampos.

    Gracias!

  3. Buenas,

    en el add_action usas dariobf_metabox

    add_action( 'add_meta_boxes', 'dariobf_metabox' );

    y luego el nombre de función es cd_meta_box_add.

    function cd_meta_box_add() {}

    ¿La función no debería llamarse dariobf_metabox?

  4. gracias por tus aportes, son muy buenos tus tutoriales, una consulta porfavor, yo ya agregué los metaboxes puse algunos campos, algo parecido al tuyo, como podría mostrar estos datos en front-end, te lo agradecería bastante si me ayudarías con eso, de ante mano una vez más, muchas gracias por aportar tus conocimientos

  5. Porque cuando agrego el código al final del archivo functions.php, la página se pone blanco, solo me ha funcionado la primera parte del tutorial con los custom post types, luego intento agregar algo y se me pone la página en blanco y se me bloquea todo, gracias

    1. Hola Jhonnatan, lee bien el tutorial, seguramente estés copiando cosas sin leer y haciéndolo mal. Te aseguro que el código funciona.

  6. Hola Dario,primero que nada, muchas gracias por compartir estos valiosos recursos.

    Te queria preguntar si es posible asignar un metabox a post de una categoria y de ser posible como se deberia hacer.

    He tratado de hacerlo ingresando por ejemplo el slug en vez de ‘page’ o ‘post’, pero no he logrado el objetivo.

    1. Hola Oscar,
      sí, es posible. Basta con aplicar el filtro sólo cuando el artículo actual pertenece a dicha categoría.

  7. Hola,

    Muchas gracias. Un post realmente útil. Solo tengo una duda. ¿qué habría que hacer si queremos que el select admita valores múltiples?.

  8. Hola AMigo, gracias por sacar tiempo y compartir sabiduria, Mi pregunta de persona nueva en el tema, en que archivo o dentro de que carpeta se coloca este codigo?

  9. Hola gracias por el tutorial. Donde se guardan los datos de los campos? osea los valores de texto de los inputs, en la bd? Osea no entiendo como funciona el metodo save… Y ademas no sabes donde puedo encontrar un tutorial sobre agregar una imagen de perfil..

  10. hola, estoy recien empezando en esto de wordpress, osea aprendiendo a crear paginas y eso, veo que explicas muy bien me gustaria que tuvieras postcat creo que seria mas entendible y porque no un curso de creacion de paginas con wordpress con funciones avanzadas, como por ejemplo ya hay paginas de anuncioss clasificados en wordpress y esas paginas requieren de muchas funcionalidades y meta-box, gracias por tus aportes.

  11. Hola, en la función:
    add_meta_box( ‘my-meta-box-id’, ‘Datos adicionales del libro’, ‘dariobf_metabox’, ‘libro’, ‘normal’, ‘high’ );

    ¿Debería ser?
    add_meta_box( ‘my-meta-box-id’, ‘Datos adicionales del libro’, ‘dariobf_meta_box_cb’, ‘libro’, ‘normal’, ‘high’ );

    Saludos.

  12. interesante articulo para los que dependemos totalmente de los plugins. pero queremos ir formándonos poco a poco, personalizar nuestro sitio y sacar el máximo partido de wp. A mi creo que aun me queda un poco grande pero voy a intentar ir aplicando estas opciones, Muchas gracias. muy bien explicado.

  13. ¡Excelente contenido! al fin un tutorial fácíl de seguir.
    Sin embargo dado las circunstancias tuve que implementarlo en un plugin personalizado, y como resultado la linea
    add_meta_box( ‘my-meta-box-id’, ‘Datos adicionales del libro’, ‘dariobf_metabox’, ‘libro’, ‘normal’, ‘high’ );
    no mostraba el Panel con el título «Datos adicionales del libro»,
    Para que funcione tuve que cambiar el parámetro ‘dariobf_metabox’ por array(‘post’) quedando de la siguiente manera:
    add_meta_box( ‘my-meta-box-id’, ‘Datos adicionales del libro’, array(‘post’), ‘libro’, ‘normal’, ‘high’ );

    Nuevamente ¡muchas gracias!
    Saludos.

  14. Mil gracias! por compartir este GRAN ARTICULO, solo te agradeceria me indiques donde puedo encontrar un ejemplo de como guardar datos desde el front-end hacia los custom y metabox, como por ejemplo un registro simple de usuarios. creo que con esto cerrarias bien el ciclo de los CT y Metas. gracias

  15. Hola Darío, muy buen artículo. Tres años después resulta súper útil.
    Tengo. Una preguntilla. Si tuviéramos que añadir JavaScript para realizar alguna acción sobre los campos del metabolismo sería en el método dariobf_meta_box_cb donde ponerlo? O utilizarías algún otro hook para incluirlo? Gracias.

  16. HOla , y a no funciona esta forma de hacer metabox?
    he hecho el primer paso y me sale error
    Fatal error: Uncaught Error: Call to undefined function add_meta_box() in C

    podrias guiarme si ahora ya no funciona de esta forma

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

*

*

DARÍO BALBONTÍN FERNÁNDEZ es el Responsable del tratamiento de los datos personales del usuario y le informa que estos datos serán tratados de conformidad con lo dispuesto en el Reglamento (UE) 2016/679 de 27 de abril (GDPR) y la Ley Orgánica 3/2018 de 5 de diciembre (LOPDGDD), por lo que se le facilita la siguiente información del tratamiento: Fin del tratamiento: mantener una relación comercial y el envío de comunicaciones sobre nuestros productos y servicios. Criterios de conservación de los datos: se conservarán mientras exista un interés mutuo para mantener el fin del tratamiento y cuando ya no sea necesario para tal fin, se suprimirán con medidas de seguridad adecuadas para garantizar la seudonimización de los datos o la destrucción total de los mismos.Comunicación de los datos: No se comunicarán los datos a terceros, salvo obligación legal. Derechos que asisten al usuario: Derecho a retirar el consentimiento en cualquier momento. Derecho de acceso, rectificación, portabilidad y supresión de sus datos y a la limitación u oposición al su tratamiento. Derecho a presentar una reclamación ante la Autoridad de control (agpd.es) si considera que el tratamiento no se ajusta a la normativa vigente. Datos de contacto para ejercer sus derechos: contacto@dariobf.com.