Artículo en vídeo


Datepicker es un calendario basado en JQuery integrado en un campo de formulario, con la finalidad de proporcionar al usuario un método cómodo y sencillo de insertar una fecha.

Cuando a un usuario se le pide insertar una fecha en un formulario web, si este no implementa unas reglas básicas o indicaciones claras, el usuario puede verse un poco perdido y no saber de qué forma insertarla:

¿Pongo el mes antes que el día?, ¿escribo el mes en números o letras?, ¿el año lo pongo con 2 o 4 cifras?, ¿separo las partes con guiones (-) o diagonales (/)?

Esto cobra aún más importancia si la fecha se va a guardar en una base de datos que espera que llegue de una forma concreta.

Para ello se implementaron herramientas como Datepicker, para que a la hora de insertar una fecha se desplegase un cómodo calendario en el que el usuario seleccionase cómodamente el mes, día y año sin errores, y todo se enviase a la base de datos debidamente procesado.

Actualmente, los navegadores web ya incorporan campos de tipo fecha <input type=»date»/>, como puedes ver en el siguiente campo:

Selecciona una fecha:

Cada navegador tiene su particular calendario, que como base, ayuda a que el usuario inserte una fecha correctamente, aunque de cara a funcionalidades más avanzadas están muy limitados.

Por ejemplo, no podemos enlazar dos campos de tipo fecha para que se comuniquen entre sí. Imagina que quieres incorporar un sistema de reserva de apartamentos en tu web, y quieres que cuando el usuario inserte la fecha de entrada, automáticamente la fecha de salida parta del día siguiente a la fecha de entrada, o que no se pueda escoger como fecha de salida, una fecha anterior a la de entrada. Con los calendarios basícos integrados por los navegadores actuales esto no es posible.

Pero con Datepicker si.

Para todo lo que requiera de una avanzada programación de fechas, Datepicker sigue siendo una excelente herramienta, y en este post vamos a ver cómo integrarlo en WordPress y cómo hacer las configuraciones más útiles dentro de cualquier sistema de reservas.

1. Descargar Datepicker

El primer paso es acudir a la web de descarga de Datepicker y descargar la última versión estable, que en el momento de escribir este post es la 1.12.1.

Tras descomprimir el ZIP, los archivos que nos interesa son:

  • jquery-ui.css
  • jquery-ui.structure.css
  • jquery-ui.theme.css
  • jquery-ui.js
  • Además, crearemos un archivo .js para nuestras propias funciones JavasScript, al que llamaremos funciones.js.

Y la carpeta images que tendremos que subir al mismo directorio que los archivos CSS.

Mi recomendación es subirlos a la misma carpeta donde se encuentra el tema activo de WordPress, es decir /wp-content/themes/tema_activo/

Y dentro crear, si no existen, dos subdirectorios, css y js.

/wp-content/themes/tema_activo/css/ donde subiremos los archivos CSS y la carpeta images de Datepicker.

/wp-content/themes/tema_activo/js/ donde subiremos el archivo .js de Datepicker y nuestro archivo funciones.js.

De tal forma que la estructura de archivos de Datepicker quede así en nuestro proyecto:

  • wp-content/themes/tema_activo/css/jquery-ui.css
  • wp-content/themes/tema_activo/css/jquery-ui-theme.css
  • wp-content/themes/tema_activo/css/jquery-ui.structure.css
  • wp-content/themes/tema_activo/css/images/
  • wp-content/themes/tema_activo/js/jquery-ui.js
  • wp-content/themes/tema_activo/js/funciones.js

2. Declarar los archivos de Datepicker en WordPress

Una vez subidos todos los archivos, necesitamos declararlos en WordPress para que este los reconozca. Lo normal es hacerlo dentro del archivo de funciones (functions.php) del tema activo, pero si es un tema que se actualiza con frecuencia, también podemos crear nuestro propio plugin de funciones y declararlo ahí de la misma forma:

function js_calendarios(){
 wp_enqueue_script('jquery');
 wp_enqueue_style('calendario-css', get_template_directory_uri().'/css/jquery-ui.css', array(), '1.0');
 wp_enqueue_style('calendario-css-2', get_template_directory_uri().'/css/jquery-ui.theme.css', array(), '1.0');
 wp_enqueue_style('calendario-css-3', get_template_directory_uri().'/css/jquery-ui.structure.css', array(), '1.0');

 wp_enqueue_script('calendario-js', get_template_directory_uri().'/js/jquery-ui.js', array('jquery'), '1.0');
 wp_enqueue_script('funciones-js', get_template_directory_uri().'/js/funciones.js', array('jquery'), '1.0');
}
add_action('wp_enqueue_scripts', 'js_calendarios');

3. Configuraciones básicas de Datepicker

Para personalizar nuestro calendario, nos vamos a dirigir a nuestro archivo funciones.js y escribimos:

$ = jQuery.noConflict();

$(document).ready(function(){
    $(function(){
        $("#datepicker1").datepicker();
    });
});

El identificador #datepicker1 es el que tenemos que usar en el campo input donde queremos que aparezca el calendario, por ejemplo:

<input type=»text» name=»fecha_entrada» id=»datepicker1″ placeholder=»Fecha de entrada»/>

Imprimiría:

Hasta aquí no difiere mucho de la funcionalidad del calendario integrado por los propios navegadores, además por defecto está inglés, tanto las cadenas de texto como el hecho de que la semana comienza en Domingo.

Vamos a comenzar definiendo las etiquetas para que aparezca en español. Para ello tenemos que añadir una serie de parámetros a la función datepicker(), tal y como se muestra en el siguiente código:

$("#datepicker1").datepicker({
   closeText: 'Cerrar',
   prevText: '< Ant',
   nextText: 'Sig >',
   currentText: 'Hoy',
   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'],
   dayNames: ['Domingo', 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado'],
   dayNamesShort: ['Dom','Lun','Mar','Mié','Juv','Vie','Sáb'],
   dayNamesMin: ['Do','Lu','Ma','Mi','Ju','Vi','Sá'], 
});

Así conseguimos que nuestro calendario ahora se vea en español:

Pero nos falta un detalle más, y es hacer que la semana comience en Lunes en lugar de Domingo, para ello añadimos el parámetro:

firstDay: 1

$("#datepicker1").datepicker({
closeText: 'Cerrar',
   prevText: '< Ant',
   nextText: 'Sig >',
   currentText: 'Hoy',
   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'],
   dayNames: ['Domingo', 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado'],
   dayNamesShort: ['Dom','Lun','Mar','Mié','Juv','Vie','Sáb'],
   dayNamesMin: ['Do','Lu','Ma','Mi','Ju','Vi','Sá'], 
   firstDay: 1, //Hace que la semana comience en Lunes
});

Y aquí el resultado:

Otra opción interesante es que no se pueda seleccionar un día anterior a la fecha actual, es decir, si hoy estamos a 10 de Diciembre de 2018, el calendario no nos va a permitir seleccionar una fecha anterior, para ello añadimos el parámetro:

minDate: 0

$("#datepicker1").datepicker({
closeText: 'Cerrar',
   prevText: '< Ant',
   nextText: 'Sig >',
   currentText: 'Hoy',
   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'],
   dayNames: ['Domingo', 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado'],
   dayNamesShort: ['Dom','Lun','Mar','Mié','Juv','Vie','Sáb'],
   dayNamesMin: ['Do','Lu','Ma','Mi','Ju','Vi','Sá'], 
   firstDay: 1, //Hace que la semana comience en Lunes
   minDate: 0, //Hace que no se puedan seleccionar fechas pasadas
});

Fijaos cómo los días anteriores aparecen en un color más transparente, indicando que no se pueden seleccionar:

Respecto al formato actual de la fecha, si seleccionamos un día en concreto veremos que el formato está definido en «mes/dia/año»:

Si queremos modificar el formato de fecha usamos el parámetro:

dateFormat: «dd/mm/yy»

$("#datepicker1").datepicker({
closeText: 'Cerrar',
   prevText: '< Ant',
   nextText: 'Sig >',
   currentText: 'Hoy',
   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'],
   dayNames: ['Domingo', 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado'],
   dayNamesShort: ['Dom','Lun','Mar','Mié','Juv','Vie','Sáb'],
   dayNamesMin: ['Do','Lu','Ma','Mi','Ju','Vi','Sá'], 
   firstDay: 1, //Hace que la semana comience en Lunes
   minDate: 0, //Hace que no se puedan seleccionar fechas pasadas
   dateFormat: "dd/mm/yy", //Establece el formato de fecha
});

Cuyo resultado sería:

Otra opción que podría resultarnos de interés es la posibilidad de cambiar el mes y el año directamente, para ello usaríamos los parámetros:

changeMonth: true,
changeYear: true,

$("#datepicker1").datepicker({
closeText: 'Cerrar',
   prevText: '< Ant',
   nextText: 'Sig >',
   currentText: 'Hoy',
   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'],
   dayNames: ['Domingo', 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado'],
   dayNamesShort: ['Dom','Lun','Mar','Mié','Juv','Vie','Sáb'],
   dayNamesMin: ['Do','Lu','Ma','Mi','Ju','Vi','Sá'], 
   firstDay: 1, //Hace que la semana comience en Lunes
   minDate: 0, //Hace que no se puedan seleccionar fechas pasadas
   dateFormat: "dd/mm/yy", //Establece el formato de fecha
   changeMonth: true, //Permite seleccionar el mes directamente
   changeYear: true, //Permite seleccionar el año directamente
});

El resultado:

4. Enlazando dos Datepickers

Hasta aquí hemos realizado configuraciones básicas, sobre todo para adaptar Datepicker al sistema de calendario español. Ahora veremos algo realmente interesante que consiste en enlazar dos calendarios Datepicker, de forma que cuando se seleccione una fecha en el Datepicker1, el Datepicker2 impida seleccionar una fecha anterior, muy interesante para sistemas de reservas.

Para ello vamos a declarar un segundo Datepicker al que llamaremos #datepicker2, con los mismos parámetros que el #datepicker1.

$("#datepicker2").datepicker({
closeText: 'Cerrar',
   prevText: '< Ant',
   nextText: 'Sig >',
   currentText: 'Hoy',
   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'],
   dayNames: ['Domingo', 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado'],
   dayNamesShort: ['Dom','Lun','Mar','Mié','Juv','Vie','Sáb'],
   dayNamesMin: ['Do','Lu','Ma','Mi','Ju','Vi','Sá'], 
   firstDay: 1, //Hace que la semana comience en Lunes
   minDate: 0, //Hace que no se puedan seleccionar fechas pasadas
   dateFormat: "dd/mm/yy", //Establece el formato de fecha
   changeMonth: true, //Permite seleccionar el mes directamente
   changeYear: true, //Permite seleccionar el año directamente
});

Ahora añadimos como parámetro al #datepicker1 el siguiente código:

onClose: function (selectedDate){
    $("#datepicker2").datepicker("option", "minDate", selectedDate);
}

Y como parámetro del #datepicker2 el siguiente código:

onClose: function (selectedDate){
    $("#datepicker1").datepicker("option", "maxDate", selectedDate);
}

Recuerda añadir una coma (,) al final si vas a seguir añadiendo parámetros.

Creamos un nuevo input:

<input type="text" name="fecha_salida" id="datepicker2" placeholder="Fecha de salida"/>

Y aquí el resultado, si seleccionamos como fecha de entrada el 25 de Diciembre, veremos que en fecha de salida no podemos seleccionar días anteriores al 25 de Diciembre:

Y ya para finalizar veremos una función para deshabilitar rangos de fechas, es decir, imagina que en tu web de reserva de apartamentos quieres que cuando el usuario despligue el calendario aparezcan bloqueados todos los días que esté reservado.

Para ello, previamente, tendríamos que hacer una consulta a la base de datos para traernos las fechas de entrada y salida de cada reserva y guardarlas en un vector o array:

Para la función siguiente necesitamos recoger las fechas de la base de datos y pasarlas a formato «mes/día/año».

En PHP es fácil:

<?php
    $fecha_formateada = new DateTime($fecha_sin_formatear);
    echo $fecha_formateada->format('m/d/Y');
?>

Cada grupo de fechas entrecomilladas representa un rango (fecha de entrada y fecha de salida), añadimos tantos rangos como reservas haya en la base de datos:

var RangeDates = ["01/10/2019,01/15/2019","01/17/2019,01/24/2019"];
var RangeDatesIsDisable = true;

Este ejemplo tomaría 2 rangos de fechas, compuestos por:

  1. Del 10 de Enero de 2019 al 15 de Enero de 2019.
  2. Del 17 de Enero de 2019 al 24 de Enero de 2019

Pasamos la siguiente función que hará las comprobaciones, desglosando los meses, días y años de cada fecha:

function DisableDays(date){
    var isd = RangeDatesIsDisable;
    var rd = RangeDates;
    var m = date.getMonth();
    var d = date.getDate();
    var y = date.getFullYear();

    for (i = 0; i < rd.length; i++){
        var ds = rd[i].split(',');
        var di, df;
        var m1, d1, y1, m2, d2, y2;

        if(ds.length == 1){
            di = ds[0].split('/');
            m1 = parseInt(di[0]);
            d1 = parseInt(di[1]);
            y1 = parseInt(di[2]);
            if (y1 == y &amp;&amp; m1 == (m + 1) &amp;&amp; d1 == d) return [!isd];
        }
 else if (ds.length > 1){
            di = ds[0].split('/');
            df = ds[1].split('/');
            m1 = parseInt(di[0]);
            d1 = parseInt(di[1]);
            y1 = parseInt(di[2]);
            m2 = parseInt(df[0]);
            d2 = parseInt(df[1]);
            y2 = parseInt(df[2]);

          if(y1 >= y || y <= y2){
              if ((m + 1) >= m1 &amp;&amp; (m + 1) <= m2){
             if (m1 == m2){
                 if (d >= d1 &amp;&amp; d <= d2) return [!isd];
                }
 else if(m1 == (m + 1)){
                    if (d >= d1) return [!isd];
                }
 else if(m2 == (m + 1)){
                    if (d <= d2) return [!isd];
                }
 else return [!isd];
              }
          }
        }
    }
    return [isd];
}

Y por último añadimos el parámetro: beforeShowDay: DisableDays, a los dos Datepicker, quedando finalmente ambos así:

$("#datepicker1").datepicker({
    closeText: 'Cerrar',
    prevText: '< Ant',
    nextText: 'Sig >',
    currentText: 'Hoy',
    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'],
    dayNames: ['Domingo', 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado'],
    dayNamesShort: ['Dom','Lun','Mar','Mié','Juv','Vie','Sáb'],
    dayNamesMin: ['Do','Lu','Ma','Mi','Ju','Vi','Sá'],
    firstDay: 1,
    minDate: 0,
    dateFormat: "dd/mm/yy",
    changeMonth: true,
    changeYear: true,
    beforeShowDay: DisableDays,
    onClose: function (selectedDate){
        $("#datepicker2").datepicker("option", "minDate", selectedDate); 
    }
});

$("#datepicker2").datepicker({
    closeText: 'Cerrar',
    prevText: '< Ant',
    nextText: 'Sig >',
    currentText: 'Hoy',
    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'],
    dayNames: ['Domingo', 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado'],
    dayNamesShort: ['Dom','Lun','Mar','Mié','Juv','Vie','Sáb'],
    dayNamesMin: ['Do','Lu','Ma','Mi','Ju','Vi','Sá'],
    firstDay: 1,
    minDate: 0,
    dateFormat: "dd/mm/yy",
    changeMonth: true,
    changeYear: true,
    beforeShowDay: DisableDays,
    onClose: function (selectedDate){
        $("#datepicker1").datepicker("option", "minDate", selectedDate);
    }
});

Como se aprecia al desplegar el calendario de fecha de entrada, ambos rangos aparecen deshabilitados:

Esto es solo un extracto de lo que considero es más importante y habitual configurar en cualquier sistema de reservas, pero en la documentación oficial de Datepicker encontrarás más funcionalidades, métodos y parámetros de configuración:

Espero que este post te haya sido de interés y utilidad, si es así no dudes en compartirlo o guardarlo en tus favoritos para futuras consultas.

Nos vemos en el siguiente post! 😉