En una entrada anterior vimos cómo añadir campos personalizados o custom fields al back-end de WordPress de forma elegante, haciendo uso de meta_boxes para ordenar y recoger la meta información adicional de nuestros posts.
Ahora vamos a ir un paso más allá, extendiendo esta funcionalidad y mejorando la experiencia de usuario en la administración desde el back-end. No nos limitaremos a crear los campos personalizados como “cajitas de texto”, vamos a ver con un ejemplo práctico cómo ofrecer al usuario una administración más dinámica, flexible e intuitiva.
Crearemos 3 campos personalizados: imagen, fecha y color. Para el primero implementaremos un botón que nos permita seleccionar una imagen de nuestra librería multimedia. También añadiremos la funcionalidad de borrar imagen. Para el campo fecha ofreceremos un datepicker, para que el usuario pueda escoger una fecha en un calendario. Algo parecido para el campo color, en éste caso montaremos un colorpicker para la selección de color.
Sin lugar a dudas es más dinámico generar un botón que nos dé acceso a la librería multimedia, y que nos permita subir imágenes o seleccionarla de la biblioteca, que poner un input de tipo texto donde poder establecer la URL de la imagen.
Necesitaremos agregar un archivo custom-fields.js desde el functions.php así como las librerías datepicker y colorpicker (que incluye WordPress) al action admin_enqueue_scripts:
<?php
function my_admin_scripts(){
//Agregamos nuestro JS
wp_enqueue_script( 'my_custom_fields_js', get_template_directory_uri() . '/js/custom-fields.js', array('jquery'), '1.0' );
//Agregamos la librería datepicker
wp_enqueue_script( 'jquery-ui-datepicker' );
wp_enqueue_style( 'jquery-ui-style', '//ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/base/jquery-ui.css', true);
//Agregamos la librería colorpicker y estilos
wp_enqueue_style( 'wp-color-picker' );
wp_enqueue_script( 'wp-color-picker' );
}
add_action('admin_enqueue_scripts', 'my_admin_scripts');
En el caso del datepicker, no hay estilos para el cuadro emergente con la fecha. Es necesario añadir estilos adicionales. Para este ejemplo utilizo la hoja CSS base de jquery-ui directamente desde el CDN de google.
También en el functions.php agregaremos las funciones necesarias para crear nuestros campos personalizados, como en el ejemplo que mencionábamos anteriormente:
<?php
function my_custom_fields_metabox() {
add_meta_box( 'custom-fields-metabox', 'Información relacionada Entradas', 'my_custom_fields', 'post', 'normal', 'high' );
}
add_action( 'add_meta_boxes', 'my_custom_fields_metabox' );
function my_custom_fields($post) {
//si existen se recuperan los valores de los metadatos
$custom_field_image = get_post_meta( $post->ID, 'custom_field_image', true );
$custom_field_date = get_post_meta( $post->ID, 'custom_field_date', true );
$custom_field_color = get_post_meta( $post->ID, 'custom_field_color', true );
// Se añade un campo nonce para probarlo más adelante cuando validemos
wp_nonce_field( 'custom_fields_metabox', 'custom_fields_metabox_nonce' );?>
<table width="100%" cellpadding="1" cellspacing="1" border="0">
<tr>
<td width="20%"><strong>Imagen</strong></td>
<td width="80%">
<div class="custom_media_item">
<?php
$display = "";
$media_item = get_post_meta( $post->ID, 'custom_field_image', true );
if (empty($media_item) || $media_item == "") { $display = 'display:none';}
$media_item_src = wp_get_attachment_url( $media_item );?>
<a href="#" class="button button-primary custom_media_item_upload">Subir imagen</a>
<input type="hidden" id="custom_field_image" name="custom_field_image" value="<?php echo $media_item;?>" />
<img src="<?php echo $media_item_src;?>" style="max-width:150px;<?php echo $display;?>" />
<a href="#" class="button button-primary custom_media_item_delete" style="<?php echo $display;?>">Eliminar</a>
</div>
</td>
</tr>
<tr>
<td><strong>Fecha</strong></td>
<td><input type="text" name="custom_field_date" value="<?php echo sanitize_text_field($custom_field_date);?>" class="date_picker" placeholder="dd/mm/aaaa" /></td>
</tr>
<tr>
<td><strong>Color</strong></td>
<td><input type="text" name="custom_field_color" value="<?php echo sanitize_text_field($custom_field_color);?>" class="color_picker" /></td>
</tr>
</table>
<?php }
function my_custom_fields_save_data($post_id) {
// Comprobamos si se ha definido el nonce.
if ( ! isset( $_POST['custom_fields_metabox_nonce'] ) ) {
return $post_id;
}
$nonce = $_POST['custom_fields_metabox_nonce'];
// Verificamos que el nonce es válido.
if ( !wp_verify_nonce( $nonce, 'custom_fields_metabox' ) ) {
return $post_id;
}
// Si es un autoguardado nuestro formulario no se enviará, ya que aún no queremos hacer nada.
if ( defined( 'DOING_AUTOSAVE') && DOING_AUTOSAVE ) {
return $post_id;
}
// Comprobamos los permisos de usuario.
if ( $_POST['post_type'] == 'page' ) {
if ( !current_user_can( 'edit_page', $post_id ) )
return $post_id;
} else {
if ( !current_user_can( 'edit_post', $post_id ) )
return $post_id;
}
// Vale, ya es seguro que guardemos los datos.
// Si existen entradas antiguas las recuperamos
$old_custom_field_image = get_post_meta( $post_id, 'custom_field_image', true );
$old_custom_field_date = get_post_meta( $post_id, 'custom_field_date', true );
$old_custom_field_color = get_post_meta( $post_id, 'custom_field_color', true );
// Saneamos lo introducido por el usuario.
$custom_field_image = sanitize_text_field( $_POST['custom_field_image'] );
$custom_field_date = sanitize_text_field( $_POST['custom_field_date'] );
$custom_field_color = sanitize_text_field( $_POST['custom_field_color'] );
// Actualizamos el campo meta en la base de datos.
update_post_meta( $post_id, 'custom_field_image', $custom_field_image, $old_custom_field_image );
update_post_meta( $post_id, 'custom_field_date', $custom_field_date, $old_custom_field_date );
update_post_meta( $post_id, 'custom_field_color', $custom_field_color, $old_custom_field_color );
}
add_action( 'save_post', 'my_custom_fields_save_data' );
En el caso del campo imagen comentar que lo que realmente vamos a almacenar en base de datos es el id de la imagen. Con la función wp_get_attachment_url($id) obtendremos su url y podremos mostrarla en una etiqueta imagen. También hacemos uso de una variable $display, que tendrá el valor «display:none» para que en el caso de no tener un ID de la imagen (es decir, la imagen no ha sido seleccionada aún), no nos muestre la etiqueta img ni el botón eliminar.
Y por último agregamos éste código en nuestro archivo custom-fields.js:
jQuery(document).ready(function ($) {
$('.custom_media_item_upload').on("click", function() {
var send_attachment_bkp = wp.media.editor.send.attachment;
var button = $(this);
wp.media.editor.send.attachment = function(props, attachment) {
$(button).next().val(attachment.id);
$(button).next().next().attr('src', attachment.url);
$(button).next().next().show();
$(button).next().next().next().show();
wp.media.editor.send.attachment = send_attachment_bkp;
}
wp.media.editor.open(button);
return false;
});
$('.custom_media_item_delete').on("click", function() {
var button = $(this);
$(button).hide();
$(button).prev().attr('src', '');
$(button).prev().hide();
$(button).prev().prev().val('');
return false;
});
$('.date_picker').datepicker({
firstDay: 1,
dayNames: [ "Domingo", "Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado" ],
dayNamesMin: [ "Do", "Lu", "Ma", "Mi", "Ju", "Vi", "Sa" ],
monthNames: [ "Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre" ],
monthNamesShort: [ "Ene", "Feb", "Mar", "Abr", "May", "Jun", "Jul", "Ago", "Sep", "Oct", "Nov", "Dic" ],
dateFormat: 'dd/mm/yy',
});
$('.color_picker').wpColorPicker({
defaultColor: false,
change: function(event, ui){},
clear: function() {},
hide: true,
palettes: true
});
});
Como puede observarse, en el evento “on click” del botón con la clase custom_media_item_upload abrimos la librería multimedia. Por medio de jQuery establecemos los valores id en el input custom_field_image, url en la etiqueta imagen, mostramos la etiqueta imagen con el método show(), así como el botón eliminar.
También realizamos acciones en el evento on click del botón eliminar, en este caso vaciamos los valores del atributo src de la imagen, del input custom_field_image, y con el método hide() ocultamos la etiqueta imagen y el propio botón de eliminar.
En cuanto al datepicker, podemos establecer una serie de valores como el primer día de la semana, los nombre de los días de la semana en nuestro idioma, así como el de los meses, y el formato de la fecha.
El colorpicker lo inicializamos también para el input que tiene la clase color_picker. Acepta una serie de opciones: color por defecto, si está oculto al inicio, o si tiene una paleta de colores más frecuentes en la parte inferior, así como dos funciones de callback.
Con este práctico ejemplo hemos visto cómo mejorar la experiencia de usuario en la administración de campos de entrada personalizados desde el back-end. En cualquier desarrollo a medida es primordial éste tipo de funcionalidad que aunque se tarde un poco más en desarrollar, nos hace ganar tiempo y ser más eficaces en la administración de nuestra web.