Optimización de imagenes con smushit en WordPress

Cuando tenemos una instalación de WordPress para nuestro sitio web, nuestro blog, nuestra tienda o para lo que lo usemos, a menudo tenemos un problema, el problema de las imágenes, si no se tiene el cuidado de escoger una imagen adecuada para lo que la utilizaremos llenamos nuestro sitio web de imágenes muy grandes en dimensión y espacio en disco, para saber la velocidad de nuestro sitio web podemos usar el servicio de Google “PageSpeed Insights“, en esta página nos dirá cuan rápida es nuestra página o lenta, además nos dirá en que estamos fallando. Muchas veces Google nos dice que hay que reducir el tamaño de las imágenes, ya que las imágenes tardan mucho tiempo en cargar y hacen lenta la carga de nuestro sitio web, pero muchas veces podemos pensar que las imágenes están perfectas como están ya que muestran lo que tienen que mostrar y buscar una similar puede ser una pérdida de tiempo, pueda que tengas razón, pero WordPress tiene un plugin que nos ayuda con esta tarea, se llama “WP SmushIt“, este plugin nos ayudará a reducir el tamaño de la imagen en espacio de disco sin maltratar la calidad de la imágen, este plugin le reduce cierto porcentaje a la calidad de la imagen y la deja con un tamaño adecuado sin maltratar la calidad que se tenía. Además de utilizar este plugin es recomendable redimensionar las imágenes y/o recortarlas a una dimensión suficientemente grande para que se vea bien en pantallas anchas pero no se tarde mucho en cargar en pantallas de móviles, por ejemplo, tenemos una imágen con dimensiones de 4500 x 3800 pixels, esto es muy grande para cualquier pantalla, lo recomendable es redimensionarla hasta 1200px de ancho y automáticamente se ajusta el alto, de esta manera se ha reducido el tamaño en dimensiones y tamaño en disco, luego puedes ejecutar “WP Smush It” y optimizarla aún más. Es de mensionar que “WP Smush It” es un plugin gratuito, pero tambien existe la versión premium que es de paga, con la versión gratuita puede optimizar tus imágenes por pequeños lotes, con la versión premium puede ejecutarla y optimizar todas las imágenes, además que la compresión de imágenes en la versión paga es mejor que la gratuita, pero muchas veces con la versión gratuita tenemos suficiente para que nuestro sitio web esté optimizado. Instalar este plugin es muy fácil, puedes ir a plugins, add new o agregar nuevo y en el buscador poner: WP Smushit, o wp smush.it o wp smushit, te aparecerán varias opciones y busca el que tenga muchas valoraciones, además está desarrollado por WPMU DEV, haces click en install now o instalar Wordpress smushit Una vez instalado encontrarás sus ajustes en Media o Medios, se llamará en el submenu WP Smush, ahi verás sus configuraciones, buscas un botón que dice “Bulk Smush Now” y comenzará la optimización de imágenes, luego podrás ver estadísticas de cuantas imagenes se han optimizado, cuanto se ha reducicido en las optimizaciones realizadas, tanto porcentaje como en megabytes. smush now

Como utilizar la Geolocalización con Google Maps

Hola a todos, espero se encuentren muy bien, ahora les explicaré como utilizar la API de Google Maps para usar la geolocalización. Haremos un pequeño ejemplo con HTML, CSS y JS. Para obtener más información de la API de Google Maps visita la web de oficial

Primero es de saber que utilizar la API de Google Maps hay que integrarla en nuestro documento HTML, lo hacemos llamando la librería desde el CDN de Google así

<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?v=3.exp"></script>

En el ejemplo utilizaré el Framework jQuery, pueden utilizar un CDN o un archivo local. El HTML de este ejemplo es muy simple, solo pondré el contenido del body 

<div class="map" id="mapaUbicar"></div>
<input type="text" value="" name="ubicacion" id="ubicacion">

Tenemos un div vacío y un input, he puesto el input a modo de mostrar como capturar las coordenadas y asignarselas al input, es algo bastante común en los desarrollo web de weapps. Bien, ahora les pondré un pequeño CSS para que se vea mejor el mapa y el contenido de la input.

.map {
	width:100%;
	height:450px;
}
#ubicacion {
	width:99%;
	padding:5px;
	margin:5px 0;
}

Lo que hacemos es ponerle el ancho completo y una altura al div que contendrá el mapa, a la input le ponemos un ancho, un padding y un margin, es muy sencillo el CSS.

Ahora vamos a la parte gruesa, aun que es muy sencillo también, les explicaré por partes

jQuery(document).ready(function(e) {
	//Inicializamos la detección de nuestra posición por medio de esta función
        obtener_posicion_actual();
});

He creado una función para inicializar la detección de nuestra posición actual.

obtener_posicion_actual = function(options) {
	var defaults = {
		maximumAge: 500000,
		enableHighAccuracy: true,
		timeout: 600000
	}
	jQuery.extend(defaults, options);
	
	if (navigator.geolocation) {
		navigator.geolocation.getCurrentPosition(exito, fallo, defaults);
	}
}

Esta función recibe un objeto Javascript como parámetro, también puede ir vacío, lleva 4 parámetros:

  • maximumAge: Es un valor long positivo que indica la edad máxima en milisegundos de una posible posición “cacheada” que es aceptable retornar. Por defecto en esta función he puesto que sea 50,000 milisegundos.
  • enableHighAccuracy: Es un Boolean que indica que la aplicación quiere recibir los mejores resultados posibles. Si es true y si el dispositivo es capaz de proporcionar una posición más precisa, así lo hará. Por defecto es true.
  • timeout: Es un valor long positivo que representa el máximo período de tiempo (en millisegundos) que se le permite tomar al dispositivo para retornar a una posición. Por defecto en esta función he puesto que sea 60,000 milisegundos.

Luego preguntamos si el navegador soporta la geolocalización, si es así utilizamos: navigator.geolocation.getCurrentPosition(exito, fallo, defaults); donde exito y fallo son dos funciones, una para éxito si ha logrado obtener la posición actual y la otra por si hay un fallo, se falla puede devolver 1 de 4 códigos para decirnos que es lo que pasó, pueden ser: 0, 1, 2 o 3. Les coloco el código de ambas funciones y verán que es cada código de error. El último parametro es el objeto que le pasamos a la función defaults.

function exito(pos) {         
	var coors = new google.maps.LatLng(pos.coords.latitude, pos.coords.longitude); 
	mapa = nuevo_mapa({
		id:'mapaUbicar',
		zoom: 13,
		center: coors
	}); 
	
	agregar_marcador({
		lat:pos.coords.latitude,
		lon:pos.coords.longitude
	},mapa);           
}        
	
function fallo(error) {           
	if (error.code == 0) {
		alert("Oops! No se puede obtener la posición actual.");
	}
	if (error.code == 1) {
		alert("Oops! Algo ha salido mal.");
	}
	if (error.code == 2) {
		alert("Oops! No has aceptado compartir tu posición.");
	}
	if (error.code == 3) {
		alert("Oops! Hemos superado el tiempo de espera");
	}        
}

Como vemos en código anterior, la función exito recibe como parámetro una posición, la cuál es tomada en la función que la llama, en base a la posición se obtiene en coors una latitud y longitud para ser usada en la API de Google Maps. Luego llamamos una función para crear un mapa, esta recibe un objeto:

  • id: Id del elemento HTML que contendrá el mapa, en nuestro caso la div vacía.
  • zoom: Zoom que queremos que tenga nuestro mapa al iniciarse
  • center: las coordenadas del centro que queremos ubicar, le pasamos las de nuestra posición actual.

Luego agregamos un marcador, así mostramos con un marker la posición donde nos encontramos, le pasamos la latitud y longitud para que se dibuje en el mapa.

La función fallo recibe como parámetro un código de error:

  • 0: No se puede obtener la posición actual.
  • 1: Hay algo que ha salido mal.
  • 2: No aceptaste darle permisos al navegador para que detecte tu posición actual.
  • 3: Se superó el tiempo de espera y no hubo respuesta.

Veamos la función para crear un mapa:

nuevo_mapa = function(options){
	var defaults = {
		id: '',
		zoom: 5,
		center: new google.maps.LatLng(10.386748, -75.504615),
		mapTypeId: google.maps.MapTypeId.ROADMAP
	}
	jQuery.extend(defaults, options);
   
	mapa = new google.maps.Map(document.getElementById(defaults.id), defaults);
	
	return mapa;
}

A esta función le pasamos como parámetro el objeto antes mencionado para la creación del mapa. finalmente usamos mapa = new google.maps.Map(document.getElementById(defaults.id), defaults); donde mapa es una instancia de un objeto tipo mapa de Google Maps y retornamos la variable creada para que se pueda utilizar fuera.

Ahora veamos la función que crea el marcador:

agregar_marcador = function(location,mapa) {
	var marker = new google.maps.Marker({
		position: new google.maps.LatLng(location.lat,location.lon),
		map: mapa,
		draggable: true
	});
	
	google.maps.event.addListener(marker, 'dragend', function() {
		pos = marker.getPosition();
		input = '#ubicacion';
		geocoder = new google.maps.Geocoder();
		geocoder.geocode({
			latLng: pos
		}, function(results, status){
			if (status == google.maps.GeocoderStatus.OK){
				jQuery(input).val(results[0].geometry.bounds.R.R+','+results[0].geometry.bounds.j.j);
			} else {
				alert('No se pudo determinar la posición: '+status);
			}
		});
	});
}

Esta función quizá sea la más compleja, no por la creación del marcador, sino por el listener que escucha cuando movemos el marcador. Lo primero que vemos es una variable marker, con ella agregamos el marcador al mapa, utiliza la posición que se ha capturado cuando ha obtenido nuestra posición actual, se le pasa como objeto location en esta función, luego se le pasa la referencia al mapa que se está utilizando y finalmente el parámetro draggable : true para que el marker se pueda arrastrar dentro del mapa.

Luego vemos un addListener que es un metodo de un objeto de Google Maps, se le pasa como parámetro el marcador, el evento a escuchar ‘dragend’ (Finalización del arrastrado por así traducirlo) y un callback, creamos una función anónima, con pos = marker.getPosition(); obtenemos la posición donde soltamos el marcador luego de arrastrarlo, luego creamos un objeto geocoder, le pasamos latLng, o sea, la posición donde se soltó el marker y una función haciendo de callback, esta función se le pasa un result y un status.

Verificamos que el staus sea el adecuado, en este caso buscamos un OK, entonces le asignamos la posición del marker al input, al result en la posicón 0 buscamos el objeto geometry, luego el objeto bounds, luego el bojeto R y finalmente el objeto R y ese valor almacenado en ese objeto le pasamos como latitud, para la longitud es de igualmanera, pero en lugar de R usamos j. Si la respuesta del status es diferente a OK mostraremos un alert indicando que no se pudo obtener la posición y nos agrega el status obtenido.

El código completo de Javascript sería así:

jQuery(document).ready(function(e) {
	obtener_posicion_actual();
});
		
agregar_marcador = function(location,mapa) {
	var marker = new google.maps.Marker({
		position: new google.maps.LatLng(location.lat,location.lon),
		map: mapa,
		draggable: true
	});
	
	google.maps.event.addListener(marker, 'dragend', function() {
		pos = marker.getPosition();
		input = '#ubicacion';
		geocoder = new google.maps.Geocoder();
		geocoder.geocode({
			latLng: pos
		}, function(results, status){
			if (status == google.maps.GeocoderStatus.OK){
				jQuery(input).val(results[0].geometry.bounds.R.R+','+results[0].geometry.bounds.j.j);
			} else {
				alert('No se pudo determinar la posición: '+status);
			}
		});
	});
}

nuevo_mapa = function(options){
	var defaults = {
		id: '',
		zoom: 5,
		center: new google.maps.LatLng(10.386748, -75.504615),
		mapTypeId: google.maps.MapTypeId.ROADMAP
	}
	jQuery.extend(defaults, options);
   
	mapa = new google.maps.Map(document.getElementById(defaults.id), defaults);
	
	return mapa;
}

function exito(pos) {         
	var coors = new google.maps.LatLng(pos.coords.latitude, pos.coords.longitude); 
	mapa = nuevo_mapa({
		id:'mapaUbicar',
		zoom: 13,
		center: coors
	}); 
	
	agregar_marcador({
		lat:pos.coords.latitude,
		lon:pos.coords.longitude
	},mapa);           
}        
	
function fallo(error) {           
	if (error.code == 0) {
		alert("Oops! No se puede obtener la posición actual.");
	}
	if (error.code == 1) {
		alert("Oops! Algo ha salido mal.");
	}
	if (error.code == 2) {
		alert("Oops! No has aceptado compartir tu posición.");
	}
	if (error.code == 3) {
		alert("Oops! Hemos superado el tiempo de espera");
	}        
}      
		
obtener_posicion_actual = function(options) {
	var defaults = {
		maximumAge: 500000,
		enableHighAccuracy: true,
		timeout: 600000,
		puntos : false
	}
	jQuery.extend(defaults, options);
	
	if (navigator.geolocation) {
		navigator.geolocation.getCurrentPosition(exito, fallo, defaults);
	}
}

Esperamos que esto te sea de ayuda para tus desarrollos en Javascript y con la API de Google Maps.

Algo muy importante a destacar es que para poder usar la geolocalización de Google Maps debes ejecutar el código en un servidor, puede ser un servidor en internet o un servidor local (XAMMP, MAMP, WAMP, LAMP, Bitnami, etc)

LocalStorage, almacenamiento local con HTML5

localstorage

Seguramente ya escuchaste sobre el almacenamiento local de HTML5. Ahora veremos como utilizar LocalStorage.

Primero tenemos que tener en cuenta que LocalStorage es el almacenamiento que no expira y tiene los siguientes métodos:

  • getItem ( key )
  • setItem ( key , value )
  • removeItem ( key ).

La utilización de cada uno es muy simple, veamos el primero:

  1. getItem( key ) : Obtiene la información almacenada, se le pasa como parámetro una key que nosotros hayamos escogido al momento de guardarla, de esta manera logramos diferenciarla de las demás.
  2. setItem( key, value ) : Guardamos nuestra información deseada en una LocalStorage, se le pasa un key para identificarlas y un value, este value debe ser un String, esto es muy importante, una LocalStorage solo puede guardar String.
  3. removeItem( key ) : Para eliminar una LocalStorage se le debe pasar una key, la LocalStorage no tiene tiempo de vida, si no se elimina estará ahi guardada.

Un ejemplo de como utilizar estos métodos de LocalStorage sería así:

if (window.localStorage) {
  //Agregamos un item
  localStorage.setItem("nombre_app", "pepe");
  //Obtenemos el item
  var nombre = localStorage.getItem("nombre_app");
  //Eliminamos el item
  localStorage.removeItem("nombre_app");
}
else {
  throw new Error('Tu Navegador no soporta LocalStorage :(');
}

Ahora te podrás preguntar, ¿Pero, que puedo hacer con esto? Pues, las posibilidades son infinitas, podrás hacer webapps, sitios web con personalizaciones, aplicaciones móviles, etc.

Veamos un ejemplo pequeño y práctico.

<body>
<div class="container">
	<h1>LocalStorage</h1>
	
	<form id="ingreso-notas" action="" method="post">
		<ul class="list-unstyled">
			<li>
				<label for="codigo">Código</label>
				<input type="text" id="codigo" name="name" />
			</li>
			<li>
				<label for="nombre">Nombre</label>
				<input type="text" id="nombre" name="nombre" />
			</li>
			<li>
				<label for="nota">Nota</label>
				<input type="text" id="nota" name="nota" />
			</li>
			<li>
				<input type="submit" class="btn btn-secondary" id="codigo" name="name" />
			</li>
		</ul>
	</form>
	
	<ul class="list-inline box-style">
	     <li><button type="button" id="all" class="btn btn-primary">Ver Todo</button></li>
	</ul>
	<div id="result"></div>
</div>
<script src="js/jquery.js"></script>
<script src="js/jquery.validate.min.js"></script>
<script src="js/init.js"></script>
</body>

En el código anterior creamos un formulario para almacenar registros de notas, el ejemplo es muy sencillo, creas un usuario, le asignas un código como id, un nombre y una nota, al enviar el formulario guardará la información como LocalStorage. Lo que haremos al procesar la información es que crearemos un JSON y antes de guardarlo lo convertiremos en un String, de esta manera podemos volverlo JSON y añadir o quitar registros.

/* Muestra el json en formato legible */
jQuery("#all").click(function(){
    mostrar_json();
});

/* Delegamos la edición a los botones creados dinámicamente */
jQuery('body').delegate('.edit','click',function(){
	var element = jQuery(this);
	id = element.data('id');
	editar_entrada(id);
});

/* Delegamos la eliminación a los botones creados dinámicamente */
jQuery('body').delegate('.delete','click',function(){
	var element = jQuery(this);
	id = element.data('id');
	eliminar_entrada(id);
});

/* Agrega al json más items */
//Primero validamos utilizando el plugin Validate de jQuery
jQuery("#ingreso-notas").validate({
	rules: {
		codigo:{required : true},
		nombre:{required : true, minlength : 3},
		nota:{required : true, number : true}
  	},
  	messages: {
    	codigo: "Este campo es requerido",
		nombre: "El nombre es requerido y debe tener por lo menos 3 caracteres",
		nota: "La nota es requerido y debe tener solo dígitos",
  	},
  	submitHandler: function() {
		//Obtenemos los datos del form
                var codigo = jQuery('#codigo').val();
		var nombre = jQuery('#nombre').val();
		var nota = jQuery('#nota').val();
                
                //Creamos el JSON
		registro = {'codigo' : codigo, 'nombre' : nombre, 'nota' : nota};
                //Agregamos el registro al LocalStorage
		localStorage.setItem(codigo,JSON.stringify(registro));
                
                //Mostramos el resultado en la tabla
		mostrar_json();
		jQuery("form").get(0).reset()
		return false;
  	}
});

function editar_entrada(id){
	var nota;
        //Recorremos todos los datos de LocalStorage que tiene nuestro navegador
	for(i = 0; i < localStorage.length; i++){
		var registro = localStorage.key(i);

                //Comparamos si es e que estamos buscando y lo agregamos al formulario para poder editarlo
		if( registro == id ){
			nota = $.parseJSON(localStorage.getItem(registro));
			jQuery('#codigo').val(nota.codigo);
			jQuery('#nombre').val(nota.nombre);
			jQuery('#nota').val(nota.nota);
		}
	}
}

function eliminar_entrada(id){
	localStorage.removeItem(id);
	jQuery('#result').html('<div class="alert">Se eliminó la entrada</div>').fadeIn(800).delay(3000).fadeOut(800,function(){
		mostrar_json();
	});
}

//Mostramos los datos alamacenados en el LocalStorage
function mostrar_json(){
	var table = '<table class="table table-striped">';
	table += '<thead><tr>';
	table += '<th>Código</th><th>Estudiante</th><th>Nota</th><th>Acciones</th>';
	table += '</tr></thead><tbody>';
	
	for(i = 0; i < localStorage.length; i++){
		var registro = localStorage.key(i);
		try {
			nota = jQuery.parseJSON(localStorage.getItem(registro));
	    } catch(err) {
			break;
	    }
		
		table += '<tr>';
		table += '<td>'+nota.codigo+'</td>';
		table += '<td>'+nota.nombre+'</td>';
		table += '<td>'+nota.nota+'</td>';
		table += '<td><button type="button" class="btn btn-default edit" data-id="'+nota.codigo+'">Editar</button> <button type="button" class="btn btn-default delete" data-id="'+nota.codigo+'">Eliminar</button></td>';
		table += '</tr>';
	}
	
	table += '</tbody></table>';
	
	jQuery('#result').html(table);
	jQuery('#result').css('display','block');
}

En el código anterior tenemos varias funciones, las cuales nos darán la interactividad, mostrar_json() nos mostrará la información almacenada en el LocalStorage. editar_entrada(id) nos ayuda a colocar la información correspondiente en el formulario para poder editarla. eliminar_entrada(id) nos elimina el ítem que hemos seleccionado de la tabla.

/* Delegamos la edición a los botones creados dinámicamente */
jQuery('body').delegate('.edit','click',function(){
	var element = jQuery(this);
	id = element.data('id');
	editar_entrada(id);
});

Con este trozo de código le damos la facultad de poder editar a los botones agregados dinámicamente, por ello utilizamos la función delegate de jQuery, es lo mismo para la seccion de eliminar ítem o registro.

/* Delegamos la eliminación a los botones creados dinámicamente */
jQuery('body').delegate('.delete','click',function(){
	var element = jQuery(this);
	id = element.data('id');
	eliminar_entrada(id);
});

Ahora, la parte final.

/* Agrega al json más items */
jQuery("#ingreso-notas").validate({
	rules: {
		codigo:{required : true},
		nombre:{required : true, minlength : 3},
		nota:{required : true, number : true}
  	},
  	messages: {
    	codigo: "Este campo es requerido",
		nombre: "El nombre es requerido y debe tener por lo menos 3 caracteres",
		nota: "La nota es requerido y debe tener solo digitos",
  	},
  	submitHandler: function() {
		var codigo = jQuery('#codigo').val();
		var nombre = jQuery('#nombre').val();
		var nota = jQuery('#nota').val();
		registro = {'codigo' : codigo, 'nombre' : nombre, 'nota' : nota};
		localStorage.setItem(codigo,JSON.stringify(registro));
		mostrar_json();
		jQuery("form").get(0).reset()
		return false;
  	}
});

Utilizamos un conocido plugin de jQuery para validar los campos del form, lo que nos interesa en este momento es en el método submitHandler, obtenemos la información del formulario, la convertimos a JSON y la agregamos al LocalStorage, mostramos la información actualizada en la tabla, limpiamos el formulario y ponemos un return false para que el formulario no recargue la página.

El ejemplo es sencillo y con él podemos ver en acción los 3 métodos de LocalStorage y un poco de JSON para facilitarnos las cosas. Esperamos que esto les ayude un poco a entender LocalStorage y a facilitarles el desarrollo de sus aplicaciones y sitios web.