Caso real: Vabiso.com

Portada del podcast Drupalízate
Drupalízate es un podcast semanal creado por mí, donde hablo sobre desarrollo web basado en Drupal.
El contenido central es resolver las típicas dudas que pueda tener alguien que tiene o quiere tener una web en Drupal.
Aparte de resolver dudas de "clientes", también se habla de tips, recomendaciones y buenas prácticas para el Developer que recién empiezan en este mundo.
Audio y notas del episodio

Vabiso.com es un portal de ofertas de empleo montado usando Drupal 8.

Las tecnologías básicas usadas son:

- módulo migrate + código custom para scrappear webs

- search_api + ElasticSearch + facets: para tener un motor de búsqueda muy potente

- módulos geolocation + geocoder: para los campos de latitud/longitud

- metatags + simple_sitemap: para mejoras y tener un SEO básico sin esfuerzo

 

Transcripción automática de este episodio de audio (puede contener errores)

 Hola, buenas, aquí una semana más en Drupalizate. Esta semana, como ya dije el episodio anterior, voy a hacer un caso real de un proyecto mío propio y voy a explicar cómo está hecho por dentro y por qué escogí ciertos módulos o por qué hice ciertas partes en código custom. Primero de todo, creo que no lo comenté en el episodio pasado, pero me voy a enfocar en proyectos míos propios, que son 100% míos, que el cliente soy yo mismo, básicamente por temas legales, porque comentar partes de proyectos en los que he participado, pero digamos que explicar las partes menos bonitas de algunos proyectos que son de clientes finales por temas legales no me quiero arriesgar, por lo cual, como digo, solo voy a comentar mis propios proyectos, porque como son míos, pues yo puedo decir lo que me venga en ganas de mis proyectos. Así que nada más, vamos a empezar. Esta primera semana voy a comentar sobre Babiso, babiso.com. El nombre dominio es lo de menos, es feo de cojones, pero lo que encontré libre. Es una web, bueno, es con v-a-b-i-s-o.com. La dejo en las notas del episodio, pues si la queréis ver. Como dije la semana pasada, esto es un experimento, porque esto es un podcast y no sé cómo... si, a ver, el tema de explicar cosas visuales. Cuando no se puede ver nada, es un poco complejo. Así que a ver cómo sale esta primera prueba. Este proyecto es un buscado de empleo, de ofertas de empleo. Lo que hace es como, entre comillas, Google, escribeo los contenidos de otras webs, o sea, tengo un bot que va por varias webs y en cada una de esas webs coge el contenido, título, descripción, otros datos y los guarda en nodos en Drupal. De entre los datos, el más interesante, con el que estuve jugando yo más tiempo, es el dato de la dirección o la ubicación o localización de la oferta de empleo. Pues si está en Barcelona, en España, Madrid o en México o en Berlín. En final, las ofertas de empleo acostumbran a poner la dirección en formato texto, pues ya sea la dirección de la oficina, en formato con el nombre de la calle y número, o directamente en sólo el nombre de la ciudad o el nombre del país. Así que la gracia de este proyecto era escribear contenidos de otras webs, transformar el contenido para poder geoposicionarlo en un mapa y poder tener búsquedas en un mapa. Así que los requisitos básicamente eran, bueno, este me lo marqué yo mismo, no es multidioma, es una web solo en inglés, porque por temas que sea rápido de implementar, opté por un único idioma, no me maté en que la web sea traducible. Poder indexar contenidos en español, pero la interfaz de la web es toda en inglés. Como digo, es básicamente porque en este proyecto no me interesaba que la web fuera multidioma y por temas de implementar este proyecto lo más rápido posible. Así que sólo en inglés. Segundo punto, he de tener alguna forma de escribear contenidos de otras webs, de varias webs, ya sea en formato HTML, ya sea si tiene una API disponible, leer la API y guardar estos datos en el nodos, en Drupal. Tercero, he de tener la opción, la opción no, es el requisito de tengo que tener un buscador lo más completo posible con búsquedas facetadas y que me permitan navegar por un mapa. Imaginemos el caso de, para que me entendáis, tipo Airbnb, no sé si se veis en la internet de Airbnb, pero tú te mueves por el mapa y te vas recalculando las ubicaciones de apartamentos o hoteles que están disponibles en esa zona y se muestran en un lateral, pues muy similar a esto. Si entras en babvisuo.com y haces una búsqueda, verás que tienes un mapa y cuando te mueves por el mapa o haces zoom en el mapa, se recalculan las ofertas de empleo que se ven al lado. Así que tenemos que tener un sistema de búsquedas lo más completo posible, que funcione con geoposicionamiento y que permita búsquedas con filtros facetados, porque algunas cosas las que estoy escribeando son, por ejemplo, categorías. Si es una oferta de empleo que pida tecnologías como PHP o JavaScript, o son ofertas de empleo que piden, yo que sé, que es del ámbito de sanidad y en hospitales. Escribeo palabras sueltas y las convierto en categorías. Así que tengo filtros facetados. Y el tema de que esto es una web automática con muchas URLs y voy a juguetear con temas de SEO, porque al final no voy a emitir nada de publicidad en ningún lado, solo quiero que por SEO la gente me descubra. Quiero optimizar lo máximo posible que esta web cargue rápido por tema de rendimiento y por SEO y que aunque tenga los mismos textos que las webs originales donde estoy escapando los textos, intentaré salir mejor posicionado en SEO que las webs originales. Aquí un punto tener en cuenta. En este sector, el del tema de ofertas de empleo, todo el mundo copia todo el mundo. O sea, la misma oferta de empleo está en 20 webs al mismo tiempo. Esto para Google es contenido duplicado. Las 20 webs tienen el mismo título, mismo texto, mismo todo. Así que la diferencia va a ser cómo está mostrado ese contenido dentro de la web. Si tiene h1, h2, si se muestra en formato texto o no, o si tienes meta tags bien puestos o no, entre otras cosas. Así que, bueno, juguetear con temas de SEO, que con este proyecto aprendí muchísimo en temas de SEO y también aprendí muchísimo en temas de búsquedas con Elasticsearch. Porque, como les decía antes, y vamos a empezar con esto, en las búsquedas avanzadas en Drupal tenemos por defecto BIUS, que es el módulo que está en el code, que es muy fácil de usar y te permite configurar muy flexiblemente, muy personalizado el tema de las búsquedas. El problema, que a veces se queda corto, y en el caso de tener búsquedas facetadas o búsquedas geoposicionadas, al final BIUS está haciendo consultas al MySQL de Drupal. Las búsquedas geoposicionadas consumen muchísima CPU desde el punto de vista de MySQL. Así que, bueno, básicamente se optó por usar Setsjapi, o sea, tener BIUS, que BIUS usase Setsjapi y que Setsjapi tuviera los datos indexados fuera de MySQL. Aquí bien dos opciones, o usar Solr o usar Elasticsearch. Solr, en mi caso, yo ya la había usado, no para búsquedas geoposicionadas, pero ya la había usado en varias webs de otros clientes, así que más o menos, ya sé cómo funciona. Elasticsearch, hasta ese momento, no lo había usado en ningún otro proyecto. Así que, bueno, fue la oportunidad de decir, mira, pues voy a intentar usar Elasticsearch, así aprendo cómo va. Otra cosa que vi, que cuando estoy viendo si Solr o Elasticsearch, es que las... a ver cómo digo, el código, si es que hace falta tocar código, que al final sí, me hizo falta tocar código, pero el código, o sea, las códices de Elasticsearch son mucho más amigables que las de Solr, o sea, son mucho más legibles. Interpretas mucho mejor qué está haciendo esta cuedi. En Solr lo veo como más complejo, así que es más fácil de modificar y entender qué hace la cuedi. También tiene, digamos, filtros o parámetros para el tema de búsquedas geoposicionadas, cosa que en Solr como que le falta un poco. O sea, se pueden hacer, pero digamos que en Elasticsearch está más pensado para este tipo de búsquedas. Así que es una nueva tecnología que no había tocado, me sirve para aprender de ella, y parece que el rendimiento en búsquedas geoposicionadas parece que es mejor en Elasticsearch que en Solr, así que pues, de cabeza, Elasticsearch. ¿Qué más del tema de búsquedas? Pues pocas cosas más, básicamente. Tenía filtros facetados, pero esto sí has tocado tu pal, que sepas que tenemos el módulo Facets que se integra con el módulo Setjapi y que te da ya los facets hechos. O sea, es por configuración, sin tocar código específico, que tengo este campo de taxonomía. Quedarlo como facet, ya está. O sea, no tocas código. El poco código que tuve que tocar yo fue que implementé un filtro nuevo facetado en formato mapa, que es el que si entras en la web vas a ver como mapa, y cuando navegas por el mapa, pues cada vez que te mueves o haces zoom, esto se envía en un evento Ajax, como que el facet, o sea, el facetado, ha sido modificado y se tiene que recargar los resultados de búsquedas de la BIU. ¿Por qué lo hice con módulos contribuidos y solo esta parte la hice con código custom? Pues para ahorrarme trabajo. El tema de Setjapi, búsquedas facetadas y la indexación en Elasticsearch no hice nada de código. Todo esto venía con el core o con el core y con módulos contribuidos de Drupal, lo cual significa que me ahorro mucho coste y muchas horas de trabajo. Solo implementé la parte visual del mapa como una opción de facetado. Así que hasta aquí, bien. Una mentira, también implementé que cuando se indexase, lo indexase como la tituló en GDU, porque no sé por qué, al menos en ese momento, hace como un año o dos, Elasticsearch Connector, que es el módulo que se usa en Drupal para conectarse a Setjapi con Elasticsearch, no sé por qué el campo de ubicación, o sea la tituló en GDU de ubicación, me lo interpretaba como un número, no como un campo de latitud o longitud. Así que sí que es verdad que tuve que modificar esto por código para que me lo interpretase bien. Para yo poder después en el filtro facetado usar las opciones de un campo de latitud o longitud. Básicamente porque en Elasticsearch uno de los tipos de filtros que tiene es enviar las ubicaciones de las esquinas del mapa, con lo cual cada vez que el usuario navega y mueve el mapa, yo vuelvo a enviar las esquinas del mapa y Elasticsearch me devuelve solo los ítems de dentro de esas coordenadas del mapa, con lo cual no me devuelve siempre todos los ítems de todo el mundo, sólo de la parte del país o de la ciudad que está viendo el usuario, con lo cual por rendimiento mejora muchísimo el front-end de la web. Vale, por este tema de búsquedas ya veis que casi todo es código contribuido. Una pequeña parte es código custom, pero porque había las búsquedas geoposicionadas, sino sería todo configuración, sería código custom, si solo fuera búsquedas de texto o búsquedas facetadas. Después está la parte de la migración de contenidos o de scrapping, que en muchas webs, creo que eran 10 o más de 10 webs, scrapeaba el HTML y después sí que había unas pocas, no sé, menos de 5, que eran en formato API, vale, se llamaban JSON básicamente. En las que se scrapeaba, en algunos casos, digamos que el código interno de HTML de la web tiene metatags que son como un estándar y al final, pues, digamos que en muchas webs si se usaba este estándar pues me era más fácil a mi scraperar los datos. En otras webs, en bastantes más de las que deberían, no tenían los típicos metatags y tenía que scrapear, vale, pues si el div que tiene esta clase, que tiene un enlace, el texto dentro del enlace, esto es el título. Y tenía que hacerlo de esta forma. El problema de scraperar HTML puro es que de aquí a un mes o dos o cuando cambien el frontend de la web, me van a romper el código que escapea, porque ya no va a ser un enlace que estaba dentro de este div, ahora va a estar en otra parte. Y esto me pasó. Al cabo de unos meses, algunas webs cambiaron partes de su frontend y me rompía mi código y pues habían títulos que salían en blanco o habían ubicaciones que salían en blanco porque el campo de ubicación había cambiado, valga la redundancia, su ubicación dentro de la web. O ya no era un div, era un span o un enlace, lo que fuera. Así que también me sirvió como casos prácticos de problemas que se encuentran cuando scrapeas muchas webs con muchos contenidos. Estamos hablando de que en su momento tenía más de 200 y pico mil nodos, que se están constantemente, al minuto, cada minuto estoy scrapeando y actualizando los datos de los nodos. Porque las ofertas de empleo son caducas. Caducan cada cierto tiempo y se pueden ir actualizando, por ejemplo pueden actualizar el salario, pueden actualizar y que en vez de caducar mañana, han ampliado y caducan en un mes. Así que tengo que ser cada x tiempo entrando en cada una de las ofertas y actualizando los datos si es que se han actualizado. Y esto me iba muy bien, a ver cómo explico, yo lo usé con el módulo migrate. Lo comenté en un episodio pasado, digamos que hay dos formas de hacer migraciones, o sea de coger contenidos de cosas externas al Drupal. La primera es usar el módulo migrate, que es el módulo contribuido que está dentro de Drupal y la segunda digamos que es hacer código totalmente custom. En este caso yo opté por usar el módulo migrate, básicamente porque ya lo he usado en muchas otras webs, aunque de forma nuevamente más simplista que en esta web, que digamos que habían cosas más complejas y que tuve que picar código custom para hacer unos plugins para que me hiciesen ciertas cosas. Pero en gran medida me ahorraba mucho tiempo de hacer migraciones usando el módulo migrate. Así que si son migraciones que lo que te corre prisa es que no se gaste tiempo de desarrollo, recomiendo que hagas usa que usas el módulo migrate. Sí que es verdad que esta web peca de mal rendimiento en el tema de las migraciones, porque el migrate digamos que es un poco pesado. Está pensado para hacer migraciones de una única vez o que actualice datos cada cierto tiempo, pero no que esté cada minuto ejecutándose. Esto por lo que he visto, acabas consumiendo mucho más CPU de la que deberías. Al final el módulo migrate tiene mucho código dentro, hace muchas cosas y bueno, al final realentiza un poco el tema de la migración. Si lo volviese a hacer a día de hoy, seguramente lo haría con código custom completamente, el tema de la migración y que al final del código custom básicamente haces un node save y que guarda el nodo. Y ya está. ¿Qué más? Del tema de la migración, el campo de la ubicación de la título longitud no es nada especial. Al final yo tengo un campo de texto donde copio y pego el mismo texto que está en la web de origen. ¿Cómo convierto este campo de texto que normalmente es España, coma, Barcelona, o sea el nombre de país, ciudad o nombre de ciudad o nombre de país o una dirección con el nombre de calle y número? ¿Cómo convierto esto a la título longitud? Tengo un campo en Drupal que es el módulo geolocation que me permite tener un campo de la título longitud y tengo el módulo en el orden del memoria y el geocoder que te permite especificar por configuración un campo de texto y que en el momento de guardar el nodo, ese campo de texto se convierte con unas APIs que tú configuras que APIs quieres usar, si quieres la de Google Maps por ejemplo o la de OpenStreetMaps que es gratuita, pues con qué APIs quieres que se convierta este texto a la título longitud. Así que básicamente esto no es código, es configuración, es instalar dos módulos y configurarlos. La cosa que parecía más compleja de este proyecto que es convertir datos a la título longitud realmente es la más simple. Vale, ya tenemos solucionados el tema de migaciones de contenido y el tema de búsquedas que básicamente tenemos un search API que una vez migrado el contenido en un nodo viene el search API y lee los datos del nodo y los indexa en Elasticsearch y tenemos una BIU con search API que coge los datos de Elasticsearch y los muestra en formato BIU y aquí ya tocará un poco de código para el frontend y mostrar el mapa y visualmente que se vea atractivo. La parte final que es la parte del SEO. ¿Qué me pasó? ¿Qué cosas me encontré con temas de SEO? La primera es como ese tipo de contenidos, ofertas de empleo, son caducas, caducan cada cierto tiempo y la oferta de empleo de hace seis meses no tiene ningún sentido que esté disponible porque la gente que entra allí tal como entra y ve que está caducada volverá a salir. Lo que se implementó fue un... creo que puse cada tres meses. Si la oferta ya ha caducado la eliminas, eliminas el nodo porque también como tengo muchos nodos la base de datos de Drupal de MySQL es un poco grande así que voy eliminando el contenido que ya no hace falta. El problema de eliminar contenido, o sea de nodos, que me elimina la URL, lo que significa que si ese contenido sigue indexado en Google cuando Google entra obtiene un 404 que es malo para inyeccion. Después, antes de que Google entre y tenga un 404, si un usuario de alguna forma buscando por texto en Google llega a una página de mi web que ya no existe, va a haber un 404 y básicamente hará un volver atrás y seguirá a Google, no seguirá navegando por mi web. Opté por una solución que no es la mejor, no es una de las mejores buenas prácticas, pero es la opción más simple y más rápida de implementar. Básicamente si el nodo no existe y la URL tiene cierto cierto formato, o sea básicamente sé que no existe y quiero una oferta de empleo, hago la redirección a la busca del mapa. De esta forma la gente que llega desde Google a una URL que ya no existe lo que ve es el mapa con lo cual obtengo que está navegando, no todos, pero la mayoría de usuarios siguen navegando por la web y siguen haciendo búsquedas de anda mira si yo buscaba justamente empleos de camarero en Madrid, anda pues tengo el parámetro de la de la URL y tal y más o menos me está filtrando o por Madrid o por camarero, sigo navegando. Es una forma de que el usuario intenta de que no se vaya de la web. Como digo no es la mejor práctica, no recomiendan redirigir todas las 404 a una página en concreto, pero en mi caso fue la opción más fácil. Probe también la opción de... bueno no es que la pruebe en este proyecto, pero digamos que me pillé los dedos en un proyecto de un cliente con la página 404 y las búsquedas en esta página, que en la página 404 te sale el banner de búsquedas y que allí puedes hacer de búsqueda de texto cualquier otro nodo. ¿Qué problema tuvimos en ese proyecto de cliente? De que había muchas páginas que salían 404 y el problema que teníamos es que por rendimiento la 404 que carga Rupal con el formulario de búsquedas es lento de cojones, con lo cual la web se resentía mucho y el servidor tenía un consumo de CPU muy elevado sólo por esa página. Así que sabiendo yo eso que ya me pillé los dedos con ese cliente y hemos de quitar esta página, este formulario de búsqueda, es mejor que no haya formulario de búsqueda o que hayan sólo los últimos cuatro artículos relacionados, pues en este mismo proyecto, en el de aviso, opté por mirar ni 404 de búsquedas ni nada. La 404 redirige. ¿No es lo mejor por SEO? No. ¿Pero es mejor que lo que tengo ahora, que es una 404 pelada? Sí. Pues vale, adelante. Y lo que obtuve es que el usuario que entraba y ha redirigido, no todos, pero la gran mayoría, seguían navegando. Así que lo considero un triunfo. Otros temas de SEO que estuve jugando. Básicamente, a ver cómo digo, lo comentaba antes que digo, cuando escapeo webs, en algunas de ellas están usando los meta tags, que son los especificados para el tipo de flota de empleo. Digamos que, a ver cómo me explico, una página web, una url, se puede identificar que es un artículo o una receta de cocina o un producto de un e-commerce o una oferta de empleo o un usuario o otras cosas. Eso se puede especificar que en el código HTML que devuelve se incruste como un JSON, para que me entendáis, y se especifica ahí, pues esto es un artículo, el título del artículo es este, la imagen destacada del artículo es este, o es una oferta de empleo, el título de oferta de empleo es este, la ubicación de oferta de empleo es esta. Pues muchas webs de portales de empleo, muchas no, pero si unas cuantas, más de las que deberían, esto no lo usan para nada, porque son webs antiguas y esto de los meta tags que usan para ofertas de empleo es relativamente nuevo, tiene unos cuantos años, pero es entre comillas nuevo. Así que me encontré con varias webs que esto no lo tienen, con lo cual yo estoy escapeando webs que tienen este contenido y yo podía conseguir salir mejor posicionado en SEO, en Google, porque yo estaba usando su mismo contenido, pero con estas meta etiquetas que ellos no usaban. ¿Cómo se puso esto? Básicamente con el módulo meta tags, no hizo falta tocar código ninguno, ponéis el módulo meta tags, creo que había un sub módulo para específico para el tema de ofertas de empleo, pero creo que eso lo puse para el campo de ubicación, me suena a recordar, pero bueno, que básicamente que usas el módulo meta tags, que te dan los tokens y tú pones que el título del nodo es el título de la página en meta tags, que la descripción del nodo es la descripción tal y básicamente haces un mapeado de qué campos del nodo son los campos que tienen que estar en meta tags. Otra cosa que está muy bien en Drupal y para temas de SEO, el sitemap, vale, claro esto es una web que tiene muchísimas url, no me caben todos en un único sitemap, tenemos el módulo de sitemap en Drupal que es contribuido, que básicamente lo configuras y si detecta que hay muchas urls te los separa todo en varias páginas, o sea te página el sitemap, básicamente porque no caben todas en un único sitemap y también es todo configuración, no hace falta nada de código. Después me fui yo al google search console y especificé que aquí tienes este sitemap y a partir de aquí empiezas a caer al google y básicamente creo que ya está, el tema de SEO que me sirvió este proyecto mucho para aprender de temas de SEO y de webs automáticas, que básicamente esta es una web automática. Es verdad que google me penalizó y justamente por casualidad fue cuando empecé a poner publicidad, así que después saqué la publicidad y sigo penalizado, hubo un cambio de algoritmo o algo, pero pasé a tener 10 veces menos visitas de las que tenía antes, llegó un punto que sin hacer nada, o sea estaba totalmente automática, cada vez tenía más visitas hasta que llegó un momento que llegó a google y me penalizó y casualidad de la vida la semana pasada había puesto publicidad, no sé si es por la publicidad o no, pero bueno. Así que aprendí mucho de SEO y cosas a tener en cuenta para temas de SEO. Aprendí mucho de elastic search y de temas de búsquedas geoposicionadas que no se acostumbran a usar en todos los proyectos, pero me ha servido para proyectos futuros en los que tenía que hacer este tipo de búsquedas. Y también me ha servido para afinar mi código en temas de migraciones, sobre todo en migraciones que tiene en cuenta HTML, o sea de Scrapeo. Y pocos más. A comentar que esto no lo he comentado, hay la búsqueda que es el mapa, que es la que intento potenciar más en esta web, que tiene esto el mapa, una búsqueda por texto libre, que tú puedes poner camaderos y vas a ver las ofertas de empleo de camaderos en el mapa. Y si es un usuario registrado, vas a poder usar los facetados, que básicamente es un filtro por categorías, que son palabras que yo saco del texto y cuando Scrapeo, y por ejemplo pues en las categorías, pues si es de programación de PHP o lo que sea, pues te salda ahí por categorías. Esto no está del todo afinado, fue una prueba de hasta dónde podía llegar D.I.O. dando palabras clave de las ofertas de empleo, y básicamente lo puse como solo para usuarios registrados. Y nada más, creo que no me dejo nada más. No está implementado ningún sistema de pagos en esta web, aunque en un inicio tenía pensado implementarlo, pero lo que hice en vez de gastar tiempo montando un sistema de pagos para que el usuario pagase para registrarse, puse un banner de, hey, de momento es gratuito, date de alta, tienes, no sé si puse seis meses o un año gratuito. Vi que hay gente que sí que se registra, pero no he visto un gran interés, con lo cual al final he optado por dejarla optar como está y no matarme yo a poner un sistema de pagos como tal. Y creo que no me dejo nada más, ya termino con este episodio. La semana que viene, depende del feedback que me hayáis dejado del anterior episodio, pero seguramente la semana que viene sigo con otro análisis de otra web mía, que es un portal donde se ponen en contacto dos personas, o sea, para que me entendáis, como un Tinder entre comillas, muy comillas, y también una implementación en esta misma web para un tema de sistema de pago sin usar el DrupalCommerce. El usuario tenía que pagar para registrarse, así que os voy a comentar cómo se implementó y por qué se hizo de esta forma sin usar el DrupalCommerce. Y nada más, hasta la semana que viene. Chao.

¿Tienes algún proyecto en mente?

Si quieres hacer algo en Drupal tal vez puedas contratarme.

Ya sea para consultoría, desarrollo o mantenimiento de sitios web Drupal.