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.
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 );
Lenguaje del código: PHP (php)
Al desglosar los parámetros que recibe, entendemos que:
- $id el el ID del metabox. Es útil, por ejemplo, si vas a utilizar un CSS custom para darle estilos a este metabox o incluso vas a hacer algo con Javascript; sino, no tiene mucha importancia.
- $title es el título que será mostrado en la parte superior del metabox, como veremos próximamente.
- $callback es la función que dará uso a nuestro metabox, lo veremos en el siguiente punto.
- $page es donde queremos que se muestre nuestro metabox; podemos decidir que se muestre en los post, las páginas o un custom post type (nuestro caso).
- $context es dónde queremos que se muestre nuestro metabox. «normal» significará que se muestre bajo el editor de la entrada o página, «side» colocará el metabox a la barra lateral de la página de edición y «advanced» lo colocará en la misma columna que el editor, pero con algún extra que no viene al caso.
- $priority le dice a WordPress dónde cargar el metabox en el contenido. «high», «default» o «low» coloca la caja del metabox arriba, en su posición natural o abajo del todo respectivamente. Aunque todos los metaboxes de WordPress funcionan con Drag and drop, $priority no tiene demasiado sentido.
- $callback_args es de otra batalla, no lo utilizaremos aquí y no quiero complicarte demasiado con cosas que no utilizarás.
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' );
Lenguaje del código: JavaScript (javascript)
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:
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
}
Lenguaje del código: PHP (php)
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
}
Lenguaje del código: JavaScript (javascript)
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
}
Lenguaje del código: PHP (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
}
Lenguaje del código: PHP (php)
La función va cogiendo volumen, vamos por partes.
- He añadido dos select, como hemos mencionado arriba.
- He añadido, también, dos variables más ($encuadernacion y $tapa) donde recogo los datos de ambos select. Tal y como hicimos con el input del ISBN.
¿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
}
Lenguaje del código: PHP (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' );
Lenguaje del código: JavaScript (javascript)
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:
- Si la entrada se está autoguardando
- Verificar el valor nonce que hemos creado en la función dariobf_metabox_content
- 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;
}
}
Lenguaje del código: PHP (php)
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 );
}
Lenguaje del código: PHP (php)
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.
Interesante, ¿en qué proyecto fue?, ¿está online?
Por cierto un libro sin autor no es un libro xD
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
Pues te digo que «que universo de marvel ni que pepinos», eres mi nuevo super heroe
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 :-)
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
Es muy interesante. Lo que me queda es investigar como realizar las búsquedas y ordenar a partir de los metacampos.
Gracias!
Muedes modificar la función search e indicarle que incluya esos campos.
Gracias, amigo.
Sos el puto amo de WordPress… Sabelo
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?
Hola César, gracias por el aviso. Efectivamente es un error mío.
Saludos.
Hola, muchas gracias por tu explicación la cual ya pude agragar un metabox dinamico en mi framework para facil uso :)
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
Hola Elvin, tal y como explico al final del artículo se hace con las funciones: get_post_meta o get_post_custom.
gracias en verdad por tus aportes
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
Hola Jhonnatan, lee bien el tutorial, seguramente estés copiando cosas sin leer y haciéndolo mal. Te aseguro que el código funciona.
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.
Hola Oscar,
sí, es posible. Basta con aplicar el filtro sólo cuando el artículo actual pertenece a dicha categoría.
Es posible agregar esto a una categoria, es decir no agregarlo a los post sino a la edicion de una categoria. ??
Hola Emanuel, en teoría sí puedes agregarlo a las categorías.
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?.
Hola Fran, gracias por tu comentario.
Si quieres que el select sea multiseleccionable no es un select, es otra cosa.
Hola.
Muchas gracias por explicarlo tambien me sirvio de mucho.
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?
Hola Eric, tal y como comento en la entrada, dentro del functions.php.
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..
Hola Giuliano,
los datos se almacenan en la base de datos, como campos personalizados del artículo en cuestión.
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.
Efectivamente.
jeje también pase algo de rato revisando el codigo, saludos.
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.
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.
¡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.
Excelente artículo, yo también odio la dependencia de plugins para añadir funcionalidades a un tema.
Un saludo.
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
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.
Hola David, tendrías que encolar ese script para el backend y atacar a los ids y clases de los campos de ese metabox que acabas de crear.
Buenísimo, muchas gracias por tu labor, es genial poder acceder a información tan bien explicada!
Bárbaro.
Excelente tutorial. Te felicito.
Pondré tu web en mi lista de consultas favoritas.
Saludos
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
Hola Cami, he actualizado el artículo.
Léelo de nuevo, creo que queda todo más claro.