1. Code
  2. WordPress
  3. Theme Development

Metaboxes personalizadas reutilizables Parte 3: Campos adicionales

En la Parte 1 y la Parte 2 de nuestra serie de tutoriales de plantillas de metabox personalizadas, aprendimos cómo crear una matriz de campos para iterar y crear una metabox personalizada con tus campos estándar. Ahora agreguemos un poco de JavaScript para algunos campos sofisticados pero muy útiles.
Scroll to top

Spanish (Español) translation by Andrea Jiménez (you can also view the original English article)

En la Parte 1 y la Parte 2 de nuestra serie de tutoriales de plantillas de metabox personalizadas, aprendimos cómo crear una matriz de campos para iterar y crear una metabox personalizada con tus campos estándar. Ahora agreguemos un poco de JavaScript para algunos campos sofisticados pero muy útiles.


Selector de fechas

Cada uno de los campos que estamos cubriendo en este tutorial requerirá jQuery y la interfaz de usuario de jQuery. Afortunadamente, WordPress hace que sea muy fácil de usar con wp_enqueue_script y, a partir de la versión 3.3, todas las interacciones y widgets de jQuery UI están incluidos en WordPress.

Como estamos trabajando en una página que añade jQuery, podemos omitir eso, pero necesitaremos obtener jQuery UI Datepicker. También necesitaremos crear nuestra propia hoja de estilo, ya que el CSS necesario aún no viene incluido en WordPress, aunque lo están resolviendo.

1
if(is_admin()) {
2
	wp_enqueue_script('jquery-ui-datepicker');
3
	wp_enqueue_style('jquery-ui-custom', get_template_directory_uri().'/css/jquery-ui-custom.css');
4
}

Solo necesitamos cargarlos en el administrador, y no en la parte frontal del sitio, así que envuelve las funciones en un condicional. La primera función llama al selector de fechas y también cargará jQuery UI Core. La segunda función llamará a nuestra hoja de estilos jquery-ui-custom.css desde la carpeta css del tema. La hoja de estilo de ejemplo incluida en la descarga al principio de este tutorial no requiere imágenes. También puedes crear tu propio tema de interfaz de usuario de jQuery.

Ahora veamos el elemento de la matriz que necesitamos agregar a nuestra matriz $custom_meta_fields que comenzamos en la Parte 1.

1
array(
2
	'label'	=> 'Date',
3
	'desc'	=> 'A description for the field.',
4
	'id'	=> $prefix.'date',
5
	'type'	=> 'date'
6
)

Esta matriz es casi idéntica a nuestro elemento de texto. Tiene una etiqueta principal, una descripción, un id único y se define el tipo de fecha. Solo iremos con una implementación básica del selector de fecha en nuestro ejemplo aquí, pero si necesitas mejorar tu uso del selector de fecha, también podrías agregar otra información a la matriz, como el formato preferido, la localización e intervalo de fechas, por nombrar algunos. Luego, podrías usar esa información en el siguiente script de llamada que debemos agregar al encabezado de la página:

1
add_action('admin_head','add_custom_scripts');
2
function add_custom_scripts() {
3
	global $custom_meta_fields, $post;
4
	
5
	$output = '<script type="text/javascript">

6
				jQuery(function() {';
7
				
8
	foreach ($custom_meta_fields as $field) { // loop through the fields looking for certain types

9
		if($field['type'] == 'date')
10
			$output .= 'jQuery(".datepicker").datepicker();';
11
	}
12
	
13
	$output .= '});

14
		</script&gt';
15
		
16
	echo $output;
17
}

Este bit debe agregarse fuera de la matriz $custom_meta_fields y fuera de la función de devolución de llamada show_custom_meta_box para inicializar el selector de fecha en todos los campos con la clase de "datepicker".

1
// date
2
case 'date':
3
	echo '<input type="text" class="datepicker" name="'.$field['id'].'" id="'.$field['id'].'" value="'.$meta.'" size="30" />
4
			<br /><span class="description">'.$field['desc'].'</span>';
5
break;

Este código se agregará después del último "break;" en nuestro interruptor de metabox.

  • Una entrada de texto básica
  • Agrega la clase "datepicker" para que la función jQuery encuentre
  • Opcionalmente, cambia el tipo a "fecha" para que esté listo para HTML5

Slider

A veces es necesario recopilar un número que se configura en un rango exacto o debe ser múltiplo de 5. El slider de la interfaz de usuario de jQuery es excelente para esto porque hace que sea fácil de arrastrar y deslizar hasta el número que quieras ingresar.

1
wp_enqueue_script('jquery-ui-slider');

Asegúrate de llamar al archivo js agregando esto a tus colas envueltas is_admin().

1
array(
2
	'label'	=> 'Slider',
3
	'desc'	=> 'A description for the field.',
4
	'id'	=> $prefix.'slider',
5
	'type'	=> 'slider',
6
	'min'	=> '0',
7
	'max'	=> '100',
8
	'step'	=> '5'
9
)

Nuevamente, estamos agregando esto a nuestra matriz $custom_meta_fields y hay algunas adiciones especiales.

  • 'min' será demandado para configurar el número mínimo permitido.
  • 'max' es para el número máximo permitido.
  • 'step' es para establecer qué intervalo de pasos utilizar.
1
if ($field['type'] == 'slider') {
2
	$value = get_post_meta($post->ID, $field['id'], true);
3
	if ($value == '') $value = $field['min'];
4
	$output .= '

5
			jQuery( "#'.$field['id'].'-slider" ).slider({

6
				value: '.$value.',

7
				min: '.$field['min'].',

8
				max: '.$field['max'].',

9
				step: '.$field['step'].',

10
				slide: function( event, ui ) {

11
					jQuery( "#'.$field['id'].'" ).val( ui.value );

12
				}

13
			});';
14
}

Agrega este bit de código al bucle en la función add_custom_scripts que creamos en el último tipo de campo. Esto agregará el jQuery personalizado que necesitamos para configurar el slider.

  • Obtén el valor guardado en el meta de la publicación.
  • Si el valor está vacío (porque es una publicación nueva), configura el valor en el mínimo.
  • Agrega el código jQuery a la salida de la función utilizando los valores que establecemos en la matriz.
  • El último bit indicará el valor establecido por el slider que se guardará en el campo de entrada.
1
// slider

2
case 'slider':
3
$value = $meta != '' ? $meta : '0';
4
	echo '<div id="'.$field['id'].'-slider"></div>

5
			<input type="text" name="'.$field['id'].'" id="'.$field['id'].'" value="'.$value.'" size="5" />

6
			<br /><span class="description">'.$field['desc'].'</span>';
7
break;

Una vez más, solo estamos usando un campo de texto para recibir el valor del slider.

  • Incluye un div con el mismo id establecido en jQuery para que se cree el slider.
  • La entrada se puede configurar como oculta si personalizas tu slider para mostrar el número de manera diferente.

Imagen

Desde la introducción de Post Thumbnails, configurar una imagen con un metacampo personalizado no es algo que hagamos mucho, pero de vez en cuando llega un momento en el que necesitas configurar una imagen que no sea la miniatura de la publicación, especialmente al crear un plugin que tiene en cuenta que es posible que el tema del usuario no admite post miniaturas.

Este campo agregará la capacidad de cargar una imagen o seleccionar una de la carga de medios, mostrar una vista previa de la imagen y guardar la identificación para las opciones de uso máximo.

Botón de carga JavaScript

Para que nuestro botón active el cargador de medios, necesitaremos vincularlo con un poco de javascript.

1
jQuery(function(jQuery) {
2
	
3
	jQuery('.custom_upload_image_button').click(function() {
4
		formfield = jQuery(this).siblings('.custom_upload_image');
5
		preview = jQuery(this).siblings('.custom_preview_image');
6
		tb_show('', 'media-upload.php?type=image&TB_iframe=true');
7
		window.send_to_editor = function(html) {
8
			imgurl = jQuery('img',html).attr('src');
9
			classes = jQuery('img', html).attr('class');
10
			id = classes.replace(/(.*?)wp-image-/, '');
11
			formfield.val(id);
12
			preview.attr('src', imgurl);
13
			tb_remove();
14
		}
15
		return false;
16
	});
17
	
18
	jQuery('.custom_clear_image_button').click(function() {
19
		var defaultImage = jQuery(this).parent().siblings('.custom_default_image').text();
20
		jQuery(this).parent().siblings('.custom_upload_image').val('');
21
		jQuery(this).parent().siblings('.custom_preview_image').attr('src', defaultImage);
22
		return false;
23
	});
24
25
});

Colócalos en un archivo js personalizado y colócalo dentro de sus colas envueltas is_admin().

1
wp_enqueue_script('custom-js', get_template_directory_uri().'/js/custom-js.js');

La primera función encuentra el botón que crearemos pronto con la clase "custom_upload_image_button'" y preforma algunas cosas diferentes al hacer clic.

  • Busca el campo donde guardaremos los datos y configúralo como "formfield".
  • Busca la imagen predeterminada que mostrará la vista previa de la imagen y configúrala como "preview".
  • Dile a thickbox que abra el cargador de medios donde seleccionarás tu imagen con una carga o desde el cargador de medios.
  • Recopila la URL de la imagen y configúrala como "imgurl".
  • Obtén la identificación de la imagen eliminándola de la clase de la imagen y configúrala como "id".
  • Envía el "id" al valor de "formfield".
  • Envía el "imgurl" al src de "vista previa".
  • Cierra el thickbox

La segunda función le dice al enlace que clasificaremos como "custom_clear_image_button" para borrar el valor del campo del formulario y restablecer la vista previa a nuestra imagen predeterminada.

Crear el campo

1
array(
2
	'name'	=> 'Image',
3
	'desc'	=> 'A description for the field.',
4
	'id'	=> $prefix.'image',
5
	'type'	=> 'image'
6
)

Solo necesitamos la información básica para este campo.

1
// image

2
case 'image':
3
	$image = get_template_directory_uri().'/images/image.png';	
4
	echo '<span class="custom_default_image" style="display:none">'.$image.'</span>';
5
	if ($meta) { $image = wp_get_attachment_image_src($meta, 'medium');	$image = $image[0]; }				
6
	echo	'<input name="'.$field['id'].'" type="hidden" class="custom_upload_image" value="'.$meta.'" />

7
				<img src="'.$image.'" class="custom_preview_image" alt="" /><br />

8
					<input class="custom_upload_image_button button" type="button" value="Choose Image" />

9
					<small> <a href="#" class="custom_clear_image_button">Remove Image</a></small>

10
					<br clear="all" /><span class="description">'.$field['desc'].'</span>';
11
break;

Están sucediendo algunas cosas aquí, pero con la forma en que escribimos el javascript, esto debería funcionar bastante bien sin importar cuántos campos de imagen agregues.

  • Configura la ruta de la imagen predeterminada y guárdala en un espacio oculto para usarla con el enlace de eliminación.
  • Si ya hay una imagen guardada, anótala con el tamaño medio de la imagen guardada.
  • Agrega un campo oculto para guardar el ID de la imagen.
  • Agrega la imagen de la vista previa.
  • Agrega el botón Cargar y el enlace Quitar.

Campos repetibles

Cuando realmente empieces a usar metacampos personalizados para almacenar varios tipos de datos para una publicación, eventualmente te encontrarás con la necesidad de tener varias instancias del mismo campo. Con un poco de javascript, puedes duplicar fácilmente un campo tantas veces como lo necesites, e incluso ordenarlos con arrastrar y soltar. Hay muchas maneras de usar esta funcionalidad, pero para nuestro ejemplo vamos a usar una entrada de texto básica.

Agregar/Quitar y Ordenar JavaScript

1
jQuery('.repeatable-add').click(function() {
2
	field = jQuery(this).closest('td').find('.custom_repeatable li:last').clone(true);
3
	fieldLocation = jQuery(this).closest('td').find('.custom_repeatable li:last');
4
	jQuery('input', field).val('').attr('name', function(index, name) {
5
		return name.replace(/(\d+)/, function(fullMatch, n) {
6
			return Number(n) + 1;
7
		});
8
	})
9
	field.insertAfter(fieldLocation, jQuery(this).closest('td'))
10
	return false;
11
});
12
13
jQuery('.repeatable-remove').click(function(){
14
	jQuery(this).parent().remove();
15
	return false;
16
});
17
	
18
jQuery('.custom_repeatable').sortable({
19
	opacity: 0.6,
20
	revert: true,
21
	cursor: 'move',
22
	handle: '.sort'
23
});

Puedes agregar este javascript a los js personalizados que ya creaste en el último paso.

La primera función busca el botón Agregar y agrega una nueva fila de campo en blanco al final de la lista de campos. Esto se configura genéricamente para que puedas tener tantos campos repetibles como necesites.

  • "field" es una versión clonada de la última fila del campo.
  • "fieldLocation" le recuerda al script dónde está el final de la lista.
  • Busca la entrada dentro de "field" y deja que tu valor se vacíe y agrega 1 al entero numérico que usaremos para guardar los datos como una matriz.
  • Agrega el campo después de fieldLocation.

La siguiente función le proporciona a cada botón de eliminar la capacidad de quitar esa fila cuando se hace clic en ella.

Finalmente, configuramos las listas para que se puedan ordenar y definimos un identificador para que puedas arrastrar y soltar las filas. No es necesario poner en la cola la interacción ordenable de la interfaz del usuario de jQuery porque ya se está utilizando en la página de publicación de edición.

Crear el campo

1
array(
2
	'label'	=> 'Repeatable',
3
	'desc'	=> 'A description for the field.',
4
	'id'	=> $prefix.'repeatable',
5
	'type'	=> 'repeatable'
6
)

No hay nada especial en este campo en la matriz de nuestro ejemplo. Sin embargo, podrías volverte bastante loco aquí y agregar opciones sobre qué tipo de campos se usan en la lista repetible.

1
// repeatable

2
case 'repeatable':
3
	echo '<a class="repeatable-add button" href="#">+</a>

4
			<ul id="'.$field['id'].'-repeatable" class="custom_repeatable">';
5
	$i = 0;
6
	if ($meta) {
7
		foreach($meta as $row) {
8
			echo '<li><span class="sort hndle">|||</span>

9
						<input type="text" name="'.$field['id'].'['.$i.']" id="'.$field['id'].'" value="'.$row.'" size="30" />

10
						<a class="repeatable-remove button" href="#">-</a></li>';
11
			$i++;
12
		}
13
	} else {
14
		echo '<li><span class="sort hndle">|||</span>

15
					<input type="text" name="'.$field['id'].'['.$i.']" id="'.$field['id'].'" value="" size="30" />

16
					<a class="repeatable-remove button" href="#">-</a></li>';
17
	}
18
	echo '</ul>

19
		<span class="description">'.$field['desc'].'</span>';
20
break;

Este campo requiere un bucle si hay un valor meta guardado, y ningún bucle si no lo hay.

  • El botón Agregar se puede colocar en cualquier lugar fuera del <ul>.
  • Empieza la lista desordenada con la clase que configuramos en el javascript para apuntar a los elementos que están dentro.
  • Si hay un metavalor guardado, itera cada valor y envíalo con un campo de entrada y un botón de eliminación para ese elemento de la lista.
  • Usa el entero $i para asegurarte de que se agregue un nuevo número a la matriz de nombres.
  • Si no hay un valor meta, simplemente genera un campo vacío.
  • Este es un manejo aproximado para la clasificación, pero hace el trabajo en nuestro ejemplo.

Conclusión

Si estuviste siguiendo las tres partes de esta serie hasta ahora, tu caja final debe verse así:

Custom Meta BoxCustom Meta BoxCustom Meta Box

Realmente solo descubrimos un poco de lo que se puede hacer con este método de creación de una plantilla de metabox personalizada reutilizable. Cuanto más le agregues a tu plantilla, más fácil será colocarla en cualquier proyecto en el que estés trabajando para agilizar el tiempo que le dedicas a la codificación y agilizar el proceso con un código limpio y consistente.