Cross-site Request Forgery: Dos ejemplos para entenderlo

Cross-site Request Forgery consiste en la falsificación de petición en sitios cruzados.

Ajá

¿En qué consiste?

Cross-site Request Forgery o CSRF a partir de ahora, es un tipo de exploit difícil de conseguir llevar a buen término pero no exento de riesgos, y muy altos. Voy a saltarme definiciones formales y pasar directamente a un ejemplo porque es como mejor se entiende.

En el siguiente ejemplo yo voy a ser el hacker y el objetivo es el sitio web de un despreocupado usuario que se va a llamar Jaimito. Para llevar a buen término mi jugada, necesitamos cumplir ciertos requisitos previos:

  • Conocer previamente que Jaimito tiene en su web, http://www.soyjaimito.com, código susceptible a ser explotado mediante esta técnica. Por ejemplo, un plugin o un tema.
  • Que Jaimito haya hecho login y tenga permisos suficientes (aunque muchas veces no se necesitan siquiera dichos permisos).
  • Yo, genio cutre del mal, me voy a crear otra web con un simple formulario en otro sitio, llamémosle vas-a-ver.com. Dicho formulario provocará una acción que acabará en desastre para Jaimito.
  • Seguidamente, necesitaré atraer la atención de Jaimito a mi nueva y flamante web. No es muy difícil conseguir un email de contacto de la web y enviarle uno con un link a ésta.
  • Necesitamos que Jaimito sea un poco inocentón.

El código explotable

Vamos a imaginar que en WordPress.org hay un plugin que contiene una vulnerabilidad de tipo CSRF y que Jaimito lo tiene instalado en http://www.soyjaimito.com. Vamos a suponer que el plugin no hace nada de nada pero tiene el siguiente código:

Es muy fácil: El plugin borra un usuario si $_POST['action'] === 'delete-user' y el usuario tiene suficientes permisos (en este caso, un administrador).

Aparentemente no hay problema, sólo los administradores pueden borrar el usuario que indiquen. Pero yo sé que no es así, ahora veremos porqué.

Me voy a crear mi sitio, vas-a-ver.com, que tiene el siguiente código, un sencillísimo formulario HTML, ni PHP ni nada:

Y una vista de la web:

Captura de un simple formulario que pone

Es un formulario que cuando se procesa redirige a http://www.soyjaimito.com y envía mediante un request de tipo POST dos datos:

  • user_id = 1
  • action = delete-user

Creo que ya se empieza a ver el objetivo de mi página pero si yo hiciera click sobre el botón que anuncia un regalo por la cara, no valdría de nada porque el sitio de Jaimito comprueba si tengo permisos o no. Lo que hay que hacer es atraer a Jaimito a mi web.

Como ya hemos dicho, esto no es muy difícil y además Jaimito es un poco inocente y va a picar sí o sí. En un caso más sofisticado crearíamos una web que se parezca a otra en la que Jaimito confíe, como Apple, Google o Facebook. Lleva más tiempo pero no es demasiado difícil replicar los estilos de páginas de ese tipo.

Resulta que le envío un email a Jaimito con el asunto “¡Has ganado un iPhone, Jaime! ¡Enhorabuena! Pincha aquí”. Si escribo el email con un poco de esmero y sin faltas de ortografía, Jaimito pinchará en el enlace que le he mandado y que redirige a mi web. Seguidamente Jaimito hará click en el botón pensando que ha ganado un iPhone y si ha hecho login en su página http://www.soyjaimito.com (si la utiliza mucho, normalmente lo estará) se encontrará con su web de siempre pero con una diferencia: El usuario con ID=1 se ha borrado. El usuario 1 suele ser el administrador y, sí, en este caso es también el usuario de Jaimito. ¡Desastre!

¿Cómo prevenirlo?

El método de prevención es muy sencillo y si nos acostumbramos a usarlo en cualquier formulario sin excepción, no tendremos este problema.

El método trata de usar una cadena alfanumérica generada en nuestro propio sitio que sea aleatoria y que enviemos junto con el formulario. Al procesarlo comprobaremos si dicha cadena es correcta. Si lo es, quiere decir que el formulario se ha enviado desde nuestro sitio, en otro caso sabemos que no es así.

En WordPress utilizamos los nonces. No me voy a extender mucho en la explicación pero para generar un nonce dentro de un formulario usamos la función

<?php wp_nonce_field( $action, $name, $referer, $echo ) ?>

https://codex.wordpress.org/Function_Reference/wp_nonce_field

Dicha función genera algo así:

El HTML que saca la función wp_nonce_field()

Dos campos:

  • _wpnonce: Incluye un token o cadena alfanumérica que luego comprobaremos.
  • _wp_http_referer: La URL relativa desde la que enviaremos el formulario.

Dicho esto vamos a corregir el plugin para comprobar dicho nonce. Primero usaremos la siguiente línea en el formulario que se encarga de borrar usuarios. Éste no lo he incluído en el código del plugin pero se trata de un formulario normal y corriente (no confundir con el de vas-a-ver.com, en ese no podríamos generar el nonce porque si lo hiciéramos no generaríamos una cadena válida. Sólo nuestro sitio puede generarlo).

<?php wp_nonce_field( 'delete-user', 'delete-user-nonce' ) ?>

Y aquí el código del plugin corregido:

Si el formulario lo procesamos desde wp-admin podríamos usar la siguiente función para comprobar el nonce: https://codex.wordpress.org/Function_Reference/check_admin_referer pero en realidad no tiene importancia.

En resumen:

  • WordPress genera un token llamado nonce que es único.
  • El formulario envía el token junto con los datos.
  • Al procesar el formulario comprobamos que el nonce es válido.
  • Si el token no es válido o no existe sabemos que no ha sido enviado desde nuestro sitio y puede que nos hayan engañado. En otro caso, podemos procesarlo y borrar el usuario que nos señala el formulario en el campo user_id.

 

Otro ejemplo con más gracia

Recientemente encontré una vulnerabilidad de este tipo en un plugin del repositorio. No voy a decir el plugin y además lo arreglaron en unos pocos días. El caso es más interesante que el anterior porque requiere además un poco de pillería por parte del hacker.

El código con problemas era más o menos esto:

Es una llamada AJAX (un poco simplificado) que recoge los datos de un formulario y envía un email a support-desk@es-un-mal-plugin.com. Es decir, al servicio de soporte del plugin. Incluirá también en las cabeceras el usuario que haya hecho login, en este caso vuelve a ser el pobre Jaimito.

Y este sería el formulario desde vas-a-ver.com, es decir, el formulario que yo, genio cutre del mal, he creado.

A la vista es igual que el anterior pero los datos enviados son distintos y la URL destino es ahora http://www.soyjaimito.com/wp-admin/admin-ajax.php. Así hacemos una petición AJAX en WordPress.

Al procesar el formulario viene lo curioso. Con los valores del formulario que he creado, el email se mandará con las siguientes características:

  • From: tomará el valor “Jaimito <contact@soyjaimito.com>”
  • Reply-to: email-hacker@hacker.com
  • Texto: Hola, necesito ayuda con vuestro plugin. Se me ha roto, ¿Podríais enviarme mis datos privados ya de paso? Es que he perdido la contraseña
  • Asunto: Socorro

Y el email se envía al soporte del plugin. Si Jaimito además es un usuario registrado premium, es muy probable que los de soporte vean que el email viene de Jaimito (cabecera From) pero cuando le den a responder al email, me respondan a mí (cabecera Reply-To): email-hacker@hacker.com.

Y aquí entra la picaresca y sofisticación del hacker. Los de soporte pensarán que hablan con Jaimito pero nada más lejos de la realidad. Si soy un poco espabilado les puedo sacar contraseñas o datos privados a los de soporte y hacer cosas peores que borrar usuarios de un sitio.

Todo esto parece muy rebuscado…

Lo es. Para explotar un CSRF hay que cumplir muchas, muchas condiciones y que todo vaya bien paso a paso pero como resulte ir bien nos pueden crear un problema muy gordo.

Lecturas recomendadas

Algunos casos de grandes corporaciones que se han visto afectadas con un CSRF: http://freedom-to-tinker.com/2008/09/29/popular-websites-vulnerable-cross-site-request-forgery-attacks/

Essential PHP Security de Chris Shiflett [O’Reilly]. Explica con un lenguaje sencillo las típicas vulnerabilidades web y cómo prevenirlas en PHP. Muy recomendable.

Hasta siempre, WPMU DEV. Hola Human Made

Al lío, después de cuatro años y medio dejo de trabajar para Incsub y empiezo una nueva etapa en mi vida profesional con Human Made.

wpmudev.png

Incsub es en realidad la empresa madre de WPMU DEV, Edublogs y CampusPress y durante estos 4 añazos y medio he tenido la oportunidad de trabajar en todas ellas. Puedo decir con toda seguridad que han sido los mejores años de toda mi vida, no sólo en lo profesional sino también en lo personal.

Si hablamos de mí, durante este tiempo…

  • Me he casado.
  • He viajado a Japón, Vietnam, Camboya, Tailandia, Bali, Mexico y la Riviera Maya. He visitado distintos lugaresde Europa como Francia, Inglaterra, un viaje en coche por el Tirol y otro por Escocia, Sofía, Holanda, Italia, Portugal y no sé si me dejo alguno más.
  • La reunión de Incsub en 2013 en Nueva York me la perdí porque mi avión fue cancelado. Aunque he tenido la oportunidad de conocer a muchos compañeros después de eso, me quedo con la espinita clavada en los huev…
  • He conocido a una cantidad absurda de gente relacionada con el mundo de WordPress. Algunos se han convertido en amigos cercanos.
  • He organizado la primera WordCamp en Madrid, en 2017.
  • He hecho el ridículo en todas y cada una de las fiestas de la WordCamp Europa, excepto en la de París porque no asistí.
  • Me he vuelto más negro con el humor pero también me autocensuro más, lo cual está bien y mal al mismo tiempo.
  • No me ha dado ningún ataque epiléptico en todos estos años (sí, soy un poco epiléptico y sigo medicado).
  • He desarrollado una empatía hacia movimientos como el feminismo y LGBTQIA.
  • Me he vuelto socialmente más responsable y cívico pero más crítico con todo, lo cual me llega a avinagrar el carácter un poco en algunas ocasiones. Vamos, que me estoy haciendo viejo.
  • Mucha serie pero menos cine que antes.

En cuanto a lo profesional…

  • Me adapto a cualquier tipo de proyecto con mucha más rapidez.
  • Me he acostumbrado a trabajar en remoto y aunque se sufre algunas veces no quiero volver a una oficina.
  • He mejorado mis habilidades con los tests unitarios.
  • He aparecido en varias versiones de WordPress como contributor en los créditos.
  • He mejorado bastante con JavaScript pero me queda mucho por hacer.
  • He aprendido React
  • Se me ha ido la olla con la automatización de tareas con npm, webpack, Gulp o Grunt. Me flipa.
  • He aprendido lo duro que es el soporte al cliente pero a la vez lo gratificante que puede llegar a ser. Si eres desarrollador y trabajas en una compañía con un equipo de soporte, por favor, pórtate bien con ellos, se merecen eso y muchísimo más.

La despedida de Incsub ha sido (está siendo) durísima. Se me han saltado las lágrimas (he llorado como si me hubieran restregado cebolla en las córneas) en varias ocasiones y mis compañeros no han parado de decirme lo mucho que me van a echar de menos. Me está costando horrores despedirme de ellos.

Screen Shot 2017-07-21 at 12.28.49 PM.png

Mi último día en Incsub será el 4 de agosto. Diré Hola a Human Made el día 1 de septiembre. Es un paso que doy con mucho cuidado porque sé que entro en una compañía lleno de desarrolladores buenísimos y que me va a permitir centrarme más en proyectos Open Source, aportar más a la comunidad de WordPress y, espero, aprender sin parar. Es un paso no exento de algo de miedo pero de eso trata lidiar con los cambios, ¿No? Si la etapa es tan buena como la anterior yo me daré por satisfecho.

El día 1 de septiembre paso de Incsubber a convertirme en Human.

React y Babel en Plugins de WordPress (III): Ahora con Webpack

Esta entrada pertenece a la serie React y Babel en Plugins de WordPress. Si te has perdido los anteriores, te recomiendo que les eches un vistazo:

React, Browserify y Babel en Plugins de WordPress (I)

React, Browserify y Babel en Plugins de WordPress (II): Ahora con Gulp

Además puedes ver el repositorio de la serie: https://github.com/igmoweb/react-plugin.git donde hay un branch por cada entrada de la serie.

Tarde, tardísimo llego a la tercera parte de esta serie. Desde Noviembre del año pasado lleva este post en la nevera y muchas cosas han cambiado desde entonces: Webpack sacó su versión 2 y la documentación es ahora mucho más clara. También he aprendido mucho en este tiempo y he refinado mi forma de usar Webpack. ¡Tarde pero aquí vamos!

¿Qué es eso de Webpack?

Webpack es una herramienta para crear bundles. Esto no es más que distintos archivos JavaScript procesados por Webpack y luego dispuestos en alguna parte de nuestra aplicación. Por ejemplo, con Webpack puedes recoger dos o tres ficheros .js y convertirlos a uno sólo. Y pensarás que esto ya lo hace Gulp o Grunt. Y es correcto, no tienes porqué utilizar Webpack en realidad pero es que Webpack llega mucho más lejos, es más eficiente y más rápido al procesar y además su configuración básica es enormemente sencilla. Gulp, aún siendo una gran herramienta, utiliza un sistema de pipes que puede llegar a ser desesperante, con Webpack todo se simplifica pero puedes complicarlo hasta niveles estratosféricos.

Por defecto, Webpack sólo entiende JavaScript y nada más pero gracias a la multitud de extensiones que tiene, puedes procesar Sass, React, ES6 e incluso imágenes. Básicamente todo lo que se te ocurra. Además puedes definir distintos bundles para cargar dependiendo de la página donde estés. Esto hace que sea muy adecuado si quieres afinar mucho el tamaño de descarga de tu página web.

Webpack además está preparado para funcionar en producción incluso con su propio servidor y es capaz de generar HTML estático dependiendo de la configuración. Esto no lo veremos aquí porque es bastante más complicado y prefiero hacer algo más simple. Si quieres volverte muy loco puedes usar la guía de SurviveJS: https://survivejs.com/webpack/developing/

Quizás esta imagen te aclare algo, o no:

Conceptos básicos en Webpack

Los conceptos básicos de Webpack los puedes encontrar en su documentación: https://webpack.js.org/concepts/. Estos son cuatro:

  • Entry: Es el punto de entrada de la aplicación. Éste le dice a Webpack desde dónde empezar a revisar el código a procesar para luego generar el/los bundles. Para Webpack puede haber uno o varios archivos como punto de entrada y con ellos puede generar uno o varios bundles.
  • Output: El punto de salida del proceso de Webpack, es decir, dónde tiene que poner el bundle una vez procesado.
  • Loaders: Webpack trata cada fichero como un módulo, sea .css, .html, .jpg o js pero Webpack sólo entiende JavaScript. Los loaders transforman dichos archivos en módulos que luego son añadidos a la gráfica de dependencias de Webpack (algo que funciona a nivel interno). Los loaders primero identifican qué tipo de archivos deberían ser tratados por dicho loader y luego transforman dicho fichero para ser añadidos al gráfico de dependencias. Un follón, vaya, pero creo que se entenderá un poco mejor con el ejemplo que veremos más adelante.
  • Plugins: Estos son añadidos externos que afectan sólo a ciertas partes del código. Hay plugins que van desde emitir una señal en la consola si hay un error a otros que generan templates de HTML. Usarlos es sencillo en lo básico pero pueden complicarse hasta el extremo.

Una configuración básica

Primero, en la raíz de nuestra aplicación, tendríamos que crear un fichero llamado webpack.config.js e incluir el siguiente código:

Es un ejemplo muy sencillo: Le decimos a Webpack que recoja el fichero foo.js, genere su gráfico de dependencias y una vez procesado, pase el contenido a ./dist/foo.bundle.js. Puede que foo.js sea un código pequeño pero también podría ser que dicho fichero llamara a otros mediante por ejemplo, require( ‘foo2.js’ ). De esta forma, Webpack procesará todos los  ficheros en uno sólo.

Webpack en WordPress

En esta entrada no vamos a complicarnos mucho. Bastará con el mismo código en React que teníamos en los dos posts anteriores y un plugin de WordPress básico. Vamos a olvidarnos de Gulp así que el fichero gulpfile.js lo podemos borrar y crearemos nuestro primer webpack.config.js. Así tengo yo mi estructura antes de empezar:

Es decir, hemos reemplazado gulpfile.js por webpack.config.js. El resto quedaría igual.

Ahora vamos a instalar Webpack como dependencia local:

npm install --save-dev webpack

Y crearemos nuestra primera configuración:

Si te fijas es casi igual que el ejemplo anterior: Un punto de entrada (src/index.js) y un punto de salida (build/app.js).

Recordemos que index.js contiene una aplicación hecha en React que incluye el componente App.js y lo renderiza donde queramos.

Ejecutando Webpack por primera vez

Aunque no te lo creas, estamos muy muy cerca de que Webpack funcione por primera vez y de hecho vamos a ejecutarlo con el siguiente comando:

./node_modules/.bin/webpack

Debería dar un error tal que así:

ERROR in ./src/index.js
Module parse failed: /Users/ignacio/source/vvv/www/wordpress/wp-content/plugins/react-plugin/src/index.js Unexpected token (5:16)
You may need an appropriate loader to handle this file type.
| import App from './App';
| 
| ReactDOM.render(<App />, document.getElementById('app') );
 @ multi ./src/index.js

Eso es porque index.js está escrito en una versión de JavaScript que Webpack no conoce, es decir, está escrito en React. Para que Webpack entienda React y ES6 necesitamos un loader.

Puede que te suene porque hemos trabajado ya con ellos en los dos capítulos anteriores: Vamos a necesitar el loader de Babel pero diciéndole que lo que hay escrito en nuestros .js es ES6 versión 2015 y React:

Lo único que hemos añadido es el objeto module y dentro unas rules. En este caso, le decimos a Webpack que cualquier fichero de tipo .js deberá ser tratado con el loader de Babel y las opciones indican qué tipo de ES6 vamos a usar (es2015) y que está escrito en React. Además le indicamos que esto sólo debe afectar a los ficheros contenidos dentro de ./src.

Por si no los tienes instalados todavía, puedes ejecutar lo siguiente para instalar el loader de Babel y todos los presets que necesitamos. Si ya los tenías es posible que sólo necesites instalar babel-loader pero tampoco pierdes nada ejecutando el comando completo:

npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react

Y volvemos a ejecutar:

./node_modules/.bin/webpack

Seguidamente veremos un chorizo enorme incomprensible pero si te fijas es fácil de descifrar:

Hash: b1f1b11399e955d5b009
Version: webpack 2.4.1
Time: 3880ms
Asset    Size  Chunks                    Chunk Names
app.js  739 kB       0  [emitted]  [big]  main
   [8] ./~/react-dom/lib/ReactInstrumentation.js 601 bytes {0} [built]
  [10] ./~/react-dom/lib/ReactUpdates.js 9.53 kB {0} [built]
  [19] ./~/react/lib/React.js 3.32 kB {0} [built]
  [80] ./~/react/react.js 56 bytes {0} [built]
  [81] ./src/index.js 466 bytes {0} [built]
  [82] ./src/App.js 2.29 kB {0} [built]
  [99] ./~/react-dom/index.js 59 bytes {0} [built]
 [113] ./~/react-dom/lib/ReactDOM.js 5.14 kB {0} [built]
 [172] ./~/react/lib/ReactChildren.js 6.19 kB {0} [built]
 [173] ./~/react/lib/ReactClass.js 26.9 kB {0} [built]
 [174] ./~/react/lib/ReactDOMFactories.js 5.53 kB {0} [built]
 [175] ./~/react/lib/ReactPropTypes.js 500 bytes {0} [built]
 [177] ./~/react/lib/ReactPureComponent.js 1.32 kB {0} [built]
 [178] ./~/react/lib/ReactVersion.js 350 bytes {0} [built]
 [183] multi ./src/index.js 28 bytes {0} [built]

Lo primero que nos da es un nombre de hash. A nosotros no nos va a importar demasiado en este tutorial. Luego aparece la versión de Webpack, el tiempo de procesado y a continuación la lista de bundles. En este caso sólo uno de 739Kb, app.js, que se genera a partir de toda esa lista de ficheros que vemos. Hay muchos pero entre ellos podemos distinguir dos nuestros: index.jsApp.js. El resto son de React.

Si además abrimos el fichero generado, app.js, veremos un JavaScript bastante difícil de entender. Webpack introduce un poco de JS que utiliza para cargar módulos internamente. Tampoco nos importa, lo único que tenemos que comprobar es si el plugin funciona. Para ello vamos a cargar la URL

wp-admin/admin.php?page=react-plugin

Y debería aparecer lo siguiente:

Que es lo que nos aparecía en la entrada anterior. Si tienes dudas puedes acudir al repositorio de esta serie y echarle un vistazo al branch step-3.

En resumen: Webpack ha transpilado el código React y ES6 gracias a Babel, luego genera un gráfico de dependencias y seguidamente genera el bundle final en build/app.js.

Facilitando las cosas con npm

Para que no tengamos que ejecutar el archivo binario de Webpack cada vez que queremos generar el bundle, vamos a añadir un par de scripts a package.json:

...
"scripts": {
  "watch": "webpack --watch",
  "build": "webpack -p"
},
...

Es bastante obvio lo que hacemos con esto:

npm run watch

ejecutará Webpack por primera vez y luego quedará esperando a cualquier cambio que hagamos en los ficheros del bundle.

npm run build

Preparará en bundle para producción. Esto es, dist/app.js quedará comprimido y con el menor tamaño posible. Si lo ejecutamos, veremos que el tamaño de la aplicación se reduce muchísimo (de 739 a 144 KB en mi caso).

Source Maps

Cuando estamos haciendo  debug y nuestros scripts están comprimidos, encontrar un error o seguir la traza de ejcución es muy complicado. Los Source Maps acuden al rescate en estos casos. Ayudan a mapear el fichero comprimido de forma que en el navegador podamos ver el código original (sin comprimir) y podamos crear puntos de break en la pestaña Sources del navegador.

Webpack incluye varias formas de generarlos, cada una tiene sus pros y contras. Desgraciadamente, la documentación de Webpack no explica del todo bien las diferencias y tienes que saber mucho de Source Maps (todo una ciencia) para entender cuál es el mejor para nuestro modo de trabajar. Yo voy a usar dos: Uno para desarrollo y otro para producción. El de desarrollo es más rápido de generar ya que necesitamos rapidez a la hora de hacer un rebuild mientras el de producción nos importa menos.

Source Map en desarrollo

El Source Map más rápido es eval pero tiene un problema: El navegador no ayudará a debugar sobre el código original sino sobre el código transpilado a ES5. Es decir, que no veremos React por ninguna parte sino el código de React una vez transformado a JavaScript real. Quizás nos puede venir bien para otro tipo de proyecto que no use React pero con el que tenemos entre manos no nos vale.

El siguiente que nos interesa es eval-source-map, parecido al anterior y más lento al generar pero rápido a la hora de regenerar cuando hacemos watch. Además nos permite pasear por el código original en lugar del código transpilado desde el navegador.

devtool:'eval-source-map'

Nuestro webpack.config.js quedaría así:

Ahora ejecutamos watch de nuevo y veremos que nuestro app.js ha incrementado su tamaño considerablemente. Cuando abrimos el inspector de Chrome podemos ver la siguiente estructura:

Bajo webpack:// encontramos todos los ficheros .js originales. Ahora podemos poner puntos de break en los ficheros originales, ¿O no? Pues parece que a día de hoy (28 de Abril de 2017), Chrome no los respeta así que hay que buscar otra fórmula. Entering…

debugger;

Este comando JavaScript hará que el navegador pare en el punto que queramos. Chrome detendrá la ejecución y desde ahí podemos ejecutar JavaScript línea por línea. Puedes probar donde quieras y verás los resultados: La ejecución parará en el fichero original en lugar del app.js.

Source Maps en producción

Para la versión de producción vamos a usar source-map, que es el más apropiado para estos entornos. Generará aparte un fichero .map  que le servirá al navegador para mapear todo el código original. Además, Chrome respetará los puntos de break. Es lento de generar pero no nos importa ya que el bundle para producción lo generaremos muy de vez en cuando.

¿Cómo diferenciamos si estamos preparando dicho bundle para desarrollo o producción? Con Webpack podemos pasar variables desde los scripts de package.json para indicar a Webpack si estamos trabajando con la versión de desarrollo o producción. Para ello vamos a cambiar la sección de scripts  en package.json:

"scripts": {
  "watch": "webpack --watch",
  "build": "webpack -p --env=prod"
},

El único cambio es –env=prod, con esto mandamos una variable llamada env al fichero webpack.config.js. Cuando hacemos watch, el valor de dicha variable es undefined. Para poder utilizarla sin embargo hay que cambiar un par de cosas. Primero vamos a crear un objeto común de configuración sin la propiedad devtool. Luego, dependiendo de la configuración (desarrollo/producción), añadiremos dicha propiedad. Además, module.exports dejará de ser un simple objeto para pasar a ser una función que evaluará en qué entorno nos encontramos:

Ahora tenemos dos configuraciones distintas:

  • npm run watch

    El bundle generado es mayor, los Source Maps se incluyen en el mismo fichero pero la regeneración del fichero es rápida.

  • npm run build

    El bundle ahorra mucho espacio y los Source Maps se generan en un fichero .map aparte que sólo cargará el navegador cuando abrimos el inspector.

 

Corolario

Webpack ofrece un universo ya conocido de posibilidades pero con mucha más elasticidad y eficiencia. Además la configuración es relativamente sencilla y los conceptos, aunque algo abstractos al principio, encajan liuego fácilmente una vez los comprendemos.

Podemos ir mucho más allá. Webpack ofrece plugins y loaders para:

  • CSS modular
  • Un servidor (webpack-dev-server) de desarrollo que recargará la página cuando haya un cambio en nuestro código. Hay que decir que para nuestro caso no es muy útil porque es WordPress el que maneja toda la parte backend y configurar el servidor para que recargue PHP es bastante complicado.
  • Loader de imágenes
  • Multitud de plugins para hacernos la vida más sencilla a la hora de desarrollar.

Como última recomendación, Jetpack está hecho en React y utiliza Webpack para el desarrollo (ojo, a día de hoy utiliza Webpack 1 y no el 2 por lo que hay cosas que varían en la configuración).

¡A explorar!

Dentro de WordCamp Madrid 2017

WordCamp Madrid de 2017 terminó hace dos días y algo ha cambiado en esta ciudad para mí. Mi primera WordCamp dentro del equipo organizador y me ha tocado el premio gordo: Organizador principal, el que todo lo sabe y no sabe nada; el que aparece aquí y allá pero no está en ningún sitio. Y ha sido más que satisfactorio, ha sido catártico, una experiencia cansadísima y con mucho estrés que definitivamente ha unido lazos en un grupo de gente excepcional que ha tomado su voluntariado como algo vital. Todos, sin excepción, se han involucrado hasta la médula. No sé de dónde ha salido esa gente pero no he podido tener más suerte como organizador que trabajar al lado de ellos y ahora que ha terminado se queda un pequeño vacío que sólo trabajar juntos de nuevo creo que podría llenar.

La motivación

Organizar esto no es fácil: No estás motivado por un dinero que no vas a ganar, ni siquiera por la exposición que nunca busqué en ninguna fase del proceso y que preferí dejar al margen porque el objetivo de una WordCamp debería trascender al propio organizador.

La motivación no la encuentras durante el proceso antes de que empiece el evento. Es cuando el evento sucede cuando descubres cuál era el motivo de todo esto. Esa motivación son las propias personas, la gente que va a recibir algo que tú y tu equipo ha creado incansablemente con una absoluta predisposición a hacer las cosas bien y de la forma más honesta posible. Es un regalo que envuelves durante muchos meses y cuyo envoltorio pesa toneladas pero que el público desmonta grácilmente y en pequeños pasos para que nada se rompa. Las risas, los encuentros después de tanto tiempo, personas conociéndose, las oportunidad que aprovechan muchos grupos de amigos para reunirse, gente que crece en lo personal y profesional… Todo eso es lo que hace que organizar una WordCamp merezca la pena. Y joder, echo de menos a esa gente con la que he convivido un fin de semana intenso y lleno de anécdotas.

El puzzle

Nunca me había visto como organizador principal de nada. Soy despistado y olvidadizo, me cuesta mucho quedarme con las caras y nombres, entrar a mi email suele llevar detrás una pequeña procesión de autoculpa. Cuando vi que iba a tomar las riendas de WordCamp Madrid por un año la idea me incomodaba. No tenía la menor idea de cómo iba a responder ante algo así. Tenía en mis manos una responsabilidad enorme, un evento ampliamente conocido en una capital europea importante. Si bien sigo pensando que como organizador no destaco en grandes cosas creo que hay algo que ha salido bien: Reunir a un grupo de gente muy, muy diferente y que no haya existido ni una discusión que genere fricciones dentro de él más allá de tener diferentes puntos de vista. Creo que se ha conseguido que dicho grupo fuera racional dentro de su propia entropía. Lo que pasa es que no estoy seguro si en realidad ha sido en parte por mi presencia o más bien porque este grupo estaba destinado a encajar como piezas de un puzzle.

Y luego coges y enmarcas el puzzle.

React, Browserify y Babel en Plugins de WordPress (II): Ahora con Gulp

Este post es la continuación de React, Browserify y Babel en Plugins de WordPress (I). Si has llegado aquí, te recomiendo que leas la primera parte para conocer los conceptos básicos de Browserify.

Qué es Gulp

Gulp es una herramienta basada en nodeJS para automatizar labores repetitivas durante el desarrollo de software. Por ejemplo, podríamos escribir JavaScript modularizado en distintos archivos y luego Gulp los une y los comprime en uno sólo. También para procesar hojas de estilo en SASS. Es muy, muy útil, nos ahorra mucho tiempo, errores y dolores de cabeza.

¿Podríamos usar Grunt? Sí pero para lo que queremos hacer Grunt se antoja lento. Gulp hace uso del sistema de streams de Node dando lugar a una ejecución muy rápida a la hora de tratar con archivos de gran peso.

Para qué vamos a usar Gulp

  • Para ejecutar Browserify directamente desde Gulp en lugar de ejecutar el script de npm que creamos en el post anterior. Esto tal cual no tiene ninguna ventaja, es lo que viene a continuación lo que nos beneficia.
  • Comprimir JavaScript para que ocupe menos espacio en disco y sea más rápido al cargar.
  • Crear un watcher para que cuando modifiquemos algún archivo JS, Browserify se ejecute automáticamente sin tener nosotros que ejecutarlo de nuevo desde la consola.

Nuevos paquetes para npm

Necesitamos nuevas dependencias en nuestro plugin que descargaremos desde npm. Para ello podemos ejecutar:

npm install --save-dev gulp gulp-rename gulp-uglify vinyl-source-stream watchify vinyl-buffer
  • gulp obviamente, sin él no podemos hacer nada
  • gulp-rename nos servirá para renombrar archivos más adelante
  • gulp-uglify es el compresor de JavaScript
  • vinyl-source-stream: Vinyl no es más que la representación de un archivo en un objeto. Un archivo tiene dos propiedades importantes: La ruta y el contenido. Representar un archivo en Vinyl nos permitirá recibir de Browserify todo el JS procesado y tratarlo luego para renombrarlo, comprimirlo o lo que queramos. Es un paquete altamente utilizado en Gulp que por filosofía, éste último, se mantiene simple.
  • watchify: Para crear nuestro watcher de archivos.

El archivo gulpfile.js

Bien, es hora de crear nuestro archivo, gulpfile.js donde indicaremos a Gulp cuáles son las tareas que queremos hacer. Para ello, creamos el archivo en la carpeta raíz de nuestro plugin y generamos la tarea por defecto o tarea default:

Dentro del archivo escribimos lo siguiente:


var gulp = require('gulp');

gulp.task( 'default', function() {
    console.log("Hola Gulp");
});

Antes de ejecutar Gulp, vamos a crear un nuevo script dentro de package.json, sustituyendo el script build que generamos en el post anterior:

...
"main": "index.js",
"scripts": {
   "build": "gulp default"
},
"keywords": [],
...

Ahora sólo tenemos que ejecutar

npm run build

y nos tendría que salir algo así:

Ejecución básica de Gulp

Como vemos, a Gulp sólo hay que indicarle las tareas con un callback. Para ejecutar una tarea en concreto sólo hay que ejecutar gulp nombre-de-la-tarea.

Vamos a complicar un poco la cosa y vamos a hacer que Browserify se ejecute cada vez que ejecutamos npm build.

Por pasos:

  • Generamos un bundle  a partir de Browserify (que ya instalamos en el post anterior y nos sirve también para Gulp, así como Babel). Le indicamos que el fichero de entrada se encuentra en src/index.jsLa opción debug tendrá en cuenta los Source Maps.
  • Le indicamos a Browserify que use Babel con los presets ES2015 y React. En el post anterior dicha configuración iba en el archivo .babelrc así que podemos borrar dicho archivo.
  • Ejecutamos dicho Bundle y mediante el sistema de streaming vía funciones pipe (¿Os suena de UNIX?), lo recogemos con vynil-source-stream, le cambiamos el nombre a app.js y lo mandamos a la carpeta build.

Si volvemos a ejecutar npm build, veremos que al cabo de unos segundos se vuelve a generar el archivo build/app.js.

[17:37:45] Starting 'default'...

[17:38:11] Finished 'default' after 26 s

Un momento, ¡¿26 segundos?! ¿No decíamos que Gulp era rápido? Y lo es, pero la primera ejecución es lenta. Cuando tengamos listo el watcher veremos que la tarea se ejecuta en muy pocos segundos.

Creación del watcher

Si no queremos estar ejecutando el script cada vez que hacemos un cambio lo más inteligente es crearnos un watcher.  Para eso vamos a usar una nueva tarea llamada watch.

Es parecido a la anterior tarea sólo que ahora usamos watchify para convertir el bundle en algo observable. Cada vez que se actualice un archivo, nos saldrá por pantalla el nombre del archivo y se volverá a ejecutar el bundle, esta vez en muy poco tiempo

Además agregamos un nuevo script en package.json:

...
"main": "index.js",
"scripts": {
  "build": "gulp default",
  "watch": "gulp watch"
},
"keywords": [],
...

Ejecutamos npm run watch et voilà, Gulp ejecuta primero todo el bundle pero luego queda a la espera de cambios en cualquier archivo dentro de cualquier archivo que estemos importando desde src/index.js, recursivamente.

Compresión de JavaScript

Para realizar la compresión nos ayudamos del módulo uglifysólo lo vamos a usar en la tarea default porque es posible que no queramos el código comprimido durante el desarrollo. También vamos  refactorizar un poco agrupando código repetido. Aquí lo tenemos todo y comentado:

Hemos hecho algunas cosas aquí: Hemos creado una nueva tarea, bundle, que únicamente ejecuta el bundle y que no utilizaremos directamente. Luego hemos modificado la tarea default para que primero ejecute bundle y luego recoja el archivo resultante y lo comprima. Si no lo hiciéramos así puede que Gulp lanzara primero la ejecución del bundle y a la vez intentara comprimirlo, como el bundle tarda mucho más en componerse, se ejecutaría primero la compresión y luego se sobreescribiría con la ejecución del bundle. Esto es lo bueno y lo malo de los streams en Node, que son asíncronos.

Para demostrar ese problema podemos sustituir default por esto otro:

gulp.task( 'default',  function() {
    var bundle = getBundle();
    executeBundle(bundle);

    // Recogemos el fichero del bundle creado y lo comprimimos
    return gulp.src(['./build/app.js'])
        .pipe(uglify()) // Comprimimos
        .pipe(gulp.dest('./build'));
});

Aparentemente la lógica es buena: Primero el bundle, luego la compresión. Pero como hemos dicho, Gulp no funciona así. En este caso lanzaría la ejecución del bundle y paralelamente lo comprimiría. El bundle acaba más tarde por lo que veremos en el archivo resultante un código sin comprimir.
Sólo falta ejecutar npm run watch  para desarrollar y npm run build cuando queramos sacar el código a producción. Con la segunda ejecución vemos que el fichero build/app.js está comprimido

En el próximo episodio

Reescribiremos TODO para trabajar con Webpack. El repositorio del código visto en este post se encuentra en https://github.com/igmoweb/react-plugin

React, Browserify y Babel en Plugins de WordPress (I)

Al grano. Vamos crear un plugin muy sencillo que utilice React en un menú del wp-admin. El plugin generará una página de administración y cargaremos React ahí mismo. Obviamente lo podríamos usar para crear una interfaz en el front y no sólo en el admin.

Para los más impacientes hay un repositorio donde voy poniendo el código: https://github.com/igmoweb/react-plugin/. Para ver este post en concreto hay que elegir la rama step-1.

Qué necesitamos

  • ReactEs una famosísima librería para generar interfaces de usuario. No es un todo en uno como Angular, React sólo sirve para crear la interfaz, no contiene nada para modelar datos y demás. No profundizaré mucho en React porque no es el objetivo de este post.
  • BrowserifyNos ayudará a generar un único archivo JavaScript que contiene todos los módulos necesarios. A este archivo final se le llama en inglés bundle. Browserify nos permite importar paquetes o módulos desde distintos archivos (véase React entre otros) para luego juntarlos todos en uno sólo, que es el archivo que usaremos en nuestro menú wp-admin.
  • BabelEs un transcompilador de ES6 (ECMAScript 6). Convierte código JavaScript ES6 en código ES5, que es el que entienden todos los navegadores hoy en día. Trabajar en ES6 es más fácil que en ES5, y más divertido.

¿Por qué no Webpack? Te estarás preguntando, amigo informático “listillo”. Pues porque Webpack es complicado, un monstruo, una bestia que hace DE TODO, un Browserify supervitaminado. Antes de meternos en Webpack podemos usar herramientas más sencillas como Browserify porque luego Webpack se entiende mejor.

Aquí un dibujo de cómo funciona más o menos todo a la vez:

Diagrama de React, Browserify y Babel

Requisitos previos

Tenemos que instalar Node.js en nuestro ordenador. Node incluye un gestor de paquetes llamado npm que nos servirá para gestionar las dependencias de nuestro proyecto. Como nuestro plugin utiliza React y Browserify, éstos se convierten en dependencias del plugin.

El plugin

El plugin que vamos a crear es muy sencillo: Crea un menú de administración en WordPress desde donde cargará el archivo JS que sacará por pantalla el HTML necesario gracias a React. Para esto creamos una nueva carpeta en wp-content/plugins, por ejemplo react-plugin. Ahora creamos el archivo principal del plugin (no va a haber más): react-plugin.php, y empezamos a picar código:

Es un plugin bastante tonto: Genera un menú (cuyo ID generado lo guarda como atributo de la clase React_Plugin, ahora veremos porqué) y nada más. El contenido del menú (React Plugin), es un simple div#app. Dentro de este div, React generará el código HTML.

Estado de las carpetas:

-wp-content/plugins/react-plugin
  * react-plugin.php

Instalación de dependencias

Gracias a npm, vamos a empezar a instalar todas las dependencias para nuestro proyecto. En el terminal, nos situamos en la carpeta de nuestro plugin y escribimos:

npm init -y

Esto nos genera un archivo package.json, un documento que npm necesita para saber qué instalar y qué características tiene el proyecto. Lo vamos a dejar tal cual porque no quiero meterme mucho en él, es todo un mundo.

Instalamos las dependencias:

npm install --save react react-dom

npm install --save-dev browserify babelify babel-preset-react babel-preset-es2015

Con esto, veremos que se ha creado una carpeta nueva, node_modules, donde se habrán descargado las siguientes dependencias:

  • React y ReactDOM. Éste último sirve para renderizar los componentes de React.
  • Browserify
  • Babelify: Un plugin de Browserify para transcompilar el código ES6 a ES5. Al final es Babel adaptado a Browserify, nada más
  • Babel Preset React y Babel Preset ES2015: Son paquetes de Babel que contienen la configuración necesaria para transcompilar de ES6 (la versión de Junio de 2015) a ES5. Podríamos usar otro paquete como ES2016 o ES2017 si quisiéramos una versión de ES6 más avanzada. El ES2015 es más que suficiente. El Preset de React ayuda a transcompilar el código de React a ES5 también.

Una vez todo instalado, el fichero package.json debería quedar más o menos así:

{
  "name": "react-plugin",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "react": "^15.3.2",
    "react-dom": "^15.3.2"
  },
  "devDependencies": {
    "babel-preset-es2015": "^6.16.0",
    "babel-preset-react": "^6.16.0",
    "babelify": "^7.3.0",
    "browserify": "^13.1.0"
  }
}

Estado de las carpetas:

-wp-content/plugins/react-plugin
  - node_modules
  * package.json
  * react-plugin.php

Estructura de carpetas

Dentro de la carpeta del plugin vamos a crear dos carpetas adicionales:

  • src: Aquí vamos a meter todos los archivos JS escritos en ES6 así como los componentes de React.
  • build: Con ayuda de Browserify, a partir de todo lo que hay en src + React (que está en node_modules/react), se generará un archivo app.js dentro de este directorio. Dicho archivo será el que cargaremos en nuestro menú de WordPress.

Estado de las carpetas:

-wp-content/plugins/react-plugin
  - build
  - node_modules
  - src
  * package.json
  * react-plugin.php

Componentes de React

Vamos a crear el componente principal de nuestro proyecto. Va a ser un simple Hello WordPress

src/App.js

src/index.js

Es algo bastante simple: App.js es el elemento principal de la interfaz. Es un simple div con un Hello WordPress dentro. Para crear un componente en React, extendemos simepre de la clase React.Component (en ES5 sería más feo y engorroso). export default significa que cuando queramos importar (con import from) dicho archivo desde otro fichero JS, es la clase App la que se exporta.

index.js  es el archivo principal de la aplicación. Lo que hace es importar el componente App (ya sabemos, con import from) y renderizarlo en el elemento HTML div#app. También importa React y ReactDOM para pintar en la página. Recordad que este elemento ya lo tenemos en nuestro menú de administración.

-wp-content/plugins/react-plugin
  - build
  - node_modules
  - src
     * App.js
     * index.js
  * package.json
  * react-plugin.php

Configuración de Babel

Si pusiéramos a trabajar ahora mismo a Browserify, podríamos generar el archivo build/app.js pero todo saldría en ES6, cosa que los navegadores todavía no entienden bien. Tenemos que decirle a Browserify que utilice Babel y que éste use los presets que nosotros le digamos. Para ello creamos un nuevo fichero:

.babelrc

{
  "presets": ["es2015", "react"]
}

Con esto le estamos diciendo a Babel que use los presets (que ya tenemos instalados en node_modules) ES2015 y React.

-wp-content/plugins/react-plugin
  - build
  - node_modules
  - src
    * App.js
    * index.js
  * .babelrc
  * package.json
  * react-plugin.php

Ejecución de Browserify

Emoción, vamos a generar por primera vez nuestro fichero build/app.js con su React, sus componentes y todo traducido a ES5 por un módico precio de cero maravedíes. A su vez, nuestros componentes estarán separados en sus respectivas carpetas para una mejor organización del código. Es un win-win en toda regla.

Para ello ejecutamos la siguiente sentencia en nuestro terminal:

./node_modules/.bin/browserify -t [ babelify ] src/index.js -o build/app.js

Con esto le decimos a Browserify: “Usando el plugin babelify, transforma el archivo src/index.js y todo lo que importa éste, en build/app.js. Si lo ejecutáis deberíais ver un archivo súper tocho en build/app.js.

Para no tener que ejecutar un comando tan largo, package.json tiene un apartado para crear scripts propios. Añadimos lo siguiente:

{
  "name": "react-plugin",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "browserify src/index.js -t [ babelify ] -o build/app.js"
  },
...

Ahora simplemente ejecutamos

npm run build

Y Browserify se ejecutará tal y como hemos hecho antes.

Estado de las carpetas:

-wp-content/plugins/react-plugin
  - build
    * app.js
  - node_modules
  - src
    * App.js
    * index.js
  * .babelrc
  * package.json
  * react-plugin.php

De vuelta al plugin

Vale, ya tenemos generado nuestro build/app.js pero no lo estamos usando en el plugin de ninguna manera. Hay que hacer uso de hooks y funciones de WordPress para ello. Aquí está la versión definitiva del mini plugin que hemos hecho:

Si nos fijamos, utilizando el hook admin_enqueue_scripts, añadimos nuestro build/app.js sólo en la página de nuestro plugin gracias a la comparación $this->page_id === $hook. De esta forma no agregamos nuestro JS en todas las páginas. Sólo una nota más: El script debe ir en el footer, de otra forma no funcionará, ya que en el header todavía no existe nuestro div#app.

Próximamente…

En el siguiente post vamos a adentrarnos en cómo automatizar todo esto. Es un poco fastidioso ejecutar npm build cada vez que queremos cambiar algo. Para echo, usaremos un watcher que detecte los cambios en los ficheros JS y que rehaga el build en build/app.js.

Cómo cargar módulos de Jetpack sin activarlo

En CampusPress nos dimos cuenta hace tiempo de que algunos módulos de Jetpack vienen muy bien para todos los usuarios pero no todos ellos van a activar el plugin al completo. Para no tener que sacar los módulos del código de Jetpack y utilizarlos como plugins individuales hemos dado con una fórmula para cargar sólo aquellos que nos interesan (los llamamos módulos obligatoriosmandatory en inglés) incluso si Jetpack está desactivado. El siguiente código es parecido al que utilizamos y lo que intenta es:

  • Carga el código base de Jetpack
  • Carga los módulos de Visibilidad de Widgets, Shortcodes Personalización de CSS  y los activa automáticamente.
  • Obvia el resto de los módulos. Jetpack no sabrá ni que existen.
  • Esconde Jetpack de la lista de plugins, por si alguien pretende activarlo
  • Desactiva Jetpack en caso de que estuviera activado.
  • Activa el modo developer en Jetpack

El código tiene dos problemas:

  • Los módulos que requieran conexión a WordPress.com no funcionarían. En este caso no hace falta.
  • No permite activar Jetpack por lo que el usuario no tendrá control sobre ciertas cosas que podrían serle útiles

Este código funciona en instalaciones que tengamos muy controladas. Si el usuario pretende instalar Jetpack, no va a poder hacerlo.

Jetpack_Mandatory_Modules Redux

¿Se puede mejorar? ¡Claro!

La siguiente clase deja a los usuarios activar/desactivar Jetpack pero oculta los módulos que queremos siempre tener instalados para que no toquetee por ahí:

Muy útil porque el usuario puede ahora activar y desactivar Jetpack, así como conectarse a cualquier servicio de WordPress.com pero los módulos obligatorios siempre estarán cargados.

Si siempre cargáis los mismos módulos de Jetpack para todos los clientes, este código puede ser de mucha ayuda para ahorrarnos algo de tiempo cuando creemos una nueva instalación.

WordCamp Europa 2016: Impresiones

En el año 1 después del #wpdrama (eso es 2016 en el calendario gregoriano) se celebra una vez más WordCamp Europa. Y van cuatro: Leiden, Sofía, Sevilla y ahora Viena. WCEU se hace más grande y el nivel de las charlas mejora. Se nota que la comunidad de WordPress es ya madura, el torbellino de tecnologías que se muestran es cada vez mayor y aporta una mayor riqueza a todo el ecosistema. Nuevos personajes aparecen en escena otrora ajenos a WordPress y sea por necesidad o por abrirse a otros mercados llegan con nuevas ideas que refrescan la temática de las charlas.

Pero esto de crecer tiene sus desventajas, el número de visitantes se ha duplicado respecto a Sevilla, el calor no, sólo faltaba. Hablaré de todo esto más adelante.

¿De qué se ha hablado en WCEU?

Foto de Tammie Lister (@karmatosed)
Foto de Tammie Lister (@karmatosed)

De muchísimas cosas pero sólo asistí a un pequeño porcentaje de ellas, sobre todo las dedicadas a desarrollo que para eso es lo mío. Aquí van mis highlights:

Short Talks: WordPress Hardening – Ten tips in ten minutes, What’s New in PHP7 and what to expect in PHP7.1

Son dos charlas de 10 minutos cada una. La primera de ellas trata algo que normalmente se pasa por alto: Seguridad. Algo que suele pasar con proyectos para clientes es no definir un buen acabado en materias de seguridad para prevenir ciertos problemas que terminan por surgir. Durante la charla (a velocidad del rayo) nos proponen ciertas prácticas que podemos incluir en nuestro workflow de manera casi natural y que prácticamente no afectará al tiempo de desarrollo del proyecto. Entre ellos mantener WordPress actualizado, probar nuestras copias de respaldo, permisos para usuarios y permisos de ejecución y escritura en carpetas.

La segunda charla se nos repitió a todos aquellos que asistimos a la WCEU en Sevilla el año anterior pero con algunos matices que merecen la pena. PHP7 ha llegado fuerte: Es mucho más rápido y consistente en la declaración de tipos.

 

Thinking outside the box(model) – An introduction to Flexbox

Una charla imprescindible para aprender el nuevo sistema de layout de CSS. Uno se pregunta por qué Flexbox no había llegado antes. ¿Sabéis eso de centrar verticalmente con CSS? ¿Que un div adapte dinámicamente su anchura cuando sobra espacio? ¿Qué tal si las columnas se dividan con igual anchura automáticamente cuando añadimos o quitamos alguna? Todas estas dificultades son cosas del paleolítico gracias a Flexbox y prácticamente compatible con todos los navegadores modernos.

 

Seven Times Faster : A Study in frontend Optimization

Una de mis charlas favoritas, aunque me hubiera gustado que durara más. Peter Wilson empieza mostrando una serie de estadísticas sobre el proceso de carga y renderizado en un navegador cómo desatender esto puede llevar a un descenso dramático del porcentaje de conversión. Luego puso en evidencia lo anticuado que WordPress tiene el sistema para agregar scripts o estilos y expuso algunas opciones como el precargado de CSS o cargar scripts asíncronamente. Mucha información en poquísimo tiempo, me dejó con ganas de más. Me traería a Peter un fin de semana a Madrid para que lo explicara, la verdad.

The Ultimate REST API talk

Básicamente TODO lo que necesitas saber para empezar con la REST API de WordPress. Si no sabes lo que es ya deberías estar empezando a aprender.

 

Using Composer to create manageable WordPress websites

Buena chicha aquí, y muchísima información en poco tiempo. Composer es un gestor de dependencias para PHP. Desafortunadamente no lo puedo usar mucho porque WordPress y Composer no se llevan bien a la hora de crear plugins generalistas pero es muy interesante ver cómo puede servir a la hora de abordar un proyecto para un cliente. Por otra parte la charla me redescubrió Roots.io, una completa suite de desarrollo para WordPress que tiene muy buena pinta.

 

Modernizing WordPress Search with Elasticsearch

Otra joya. Elasticsearch puede ayudar a resolver los múltiples problemas que MySQL tiene a la hora de ejecutar consultas complejas. Taylor Lovett nos explica cómo se utiliza, para qué y si es fácil utilizarlo una vez tienes tu base de datos en funcionamiento (pista: es extremadamente sencillo). Ideal para sitios grandes, nos gustaría usarlo en CampusPress o Edublogs.

 

Como ya he dicho previamente, las charlas de este año han mejorado en calidad y parece que hay más hueco para los desarrolladores un poco más experimentados. El track 2 (el segundo en tamaño) albergó una gran parte de dichas charlas con un aforo más que considerable.

 

My friend the Impostor Syndrome

Normalmente las charlas sobre comunidad, aunque necesarias, me parecen flojas porque terminan repitiendo lo que ya sabemos. De entre todas ellas me quedo con ésta. Sonja Leix habla sobre cómo nos subestimamos a la hora de contribuir dentro de una comunidad porque nos arrolla un miedo a parecer idiotas. Nos recuerda muy bien que preguntar nunca es idiota y que colaborar de la forma que sea es siempre bueno y bien aceptado. El miedo es infundado y estanca nuestro crecimiento profesional y personal. Algo que intento explicar en el Meetup de Madrid. Quizás coja algunas ideas de la charla.

Todas las charlas están disponibles aquí: https://2016.europe.wordcamp.org/schedule/track-1-livestream/

Los Polyglots en el Contributor Day de WCEU Viena 2016

Polygloting

Contributor Day

Sinceramente, este año llegué tarde al Contributor Day y sin embargo tuve tiempo para sentarme con un grupo de españoles y revisar cómo se están haciendo las cosas en el grupo de Polyglots de Español. Liderados por Luis Rull pasamos un rato buenísimo durante el cual discutimos nuestras impresiones sobre la comunidad de WordPress en España y sobre cómo mejorarla.

Un momento, que no todo es oro

Como ya he dicho, WCEU ha crecido muchísimo de un año para otro. Sorprendentemente a nivel organizativo no se ha visto afectado. Las charlas han comenzado a su hora siempre y la atención de los voluntarios ha sido ejemplar. No hay otra comunidad como la de WordPress y es en estos eventos donde se demuestra la dedicación de los voluntarios y ponentes que sin cobrar un duro pueden llegar a repartir tantísima calidad en el evento, y a precios de saldo, oiga.

Pero hay cosas que han fallado y a mi parecer algo grave. Si las charlas son interesantes, lo que pasa fuera de ellas lo es muchísimo más. Cuando terminas de ver una charla que te ha gustado lo primero que quieres hacer es probar lo que has aprendido en tu ordenador lo antes posible. Una mesa y una silla y a teclear. Al rato pasa alguien que se interesa por lo que estás haciendo, te pregunta, le preguntas, y quién sabe si acabáis haciendo un proyecto juntos. Es debido a estas cosas por las cuales tengo el trabajo que tengo y sé lo que sé. Socializar durante una WordCamp es, a mi entender, lo más importante y en Viena ha fallado estrepitosamente ¿Por qué? Simple, no había casi espacio para pararse en una mesa con tu ordenador. En este aspecto, Sofía se lleva el primer premio (sobraba muchísimo espacio) y Sevilla era acogedor y fresco. Puede que la organización pensara que podríamos sacar nuestros bártulos al patio pero hacía muchísimo calor y humedad y el aire acondicionado en el interior no era un modelo de los que nos gastamos en España. Conclusión: se conoce a poca gente.

Aplauso y medio para WCEU 2016.

wceu1

La cosa de trabajar desde casa

Trabajo desde casa desde hace ya 3 años y medio. Me encanta hacerlo pero no está exento de puntos negativos, y algunos son perjudiciales para la salud, lo sé y vivo con ello. Trabajar desde casa exige varias cosas:

1. Honestidad con el que te contrata

No es algo que sea únicamente propio de los que trabajan desde casa, más bien de muchos autónomos. En mi caso nunca me he desplazado a las oficinas de algún cliente porque dedico la mayor parte de mi tiempo a WPMU DEV e intento evitar clientes “estándar”. No te ven, no te controlan ni saben qué haces en todo el día, por eso tienes que ser brutalmente honesto. Si te has levantado con resaca y no quieres trabajar es mejor decirlo y luego recuperar todo o parte de las horas que has perdido en lugar de hacer cualquier pufo en tus facturas.

2. Fuerza de voluntad

Sinceramente, no me vería con tanta fuerza de voluntad si mi vida no fuera medianamente ordenada (no lo ha sido nunca hasta ahora). Si tu vida no lo es, lo vas a pasar mal: horarios muy locos, poca capacidad para organizar tu vida y vacaciones… Cuando era estudiante, mis jornadas en la biblioteca eran maratonianas y nocturnas. La noche puede ser muy tranquila para alguien que trabaja en casa pero no es nada recomendable, no hay nada como la oscuridad para convertirse en un psicópata.

3. No necesitar de nadie para alegrarte el día

Soy una persona sociable y afortunadamente tengo suficientes amistades como para pasar los fines de semana tomando algo o apartarme de Madrid con alguna excursión pero no necesito a nadie a mi lado para entretenerme o mantener la concentración. No echo de menos los paseos a la máquina de café con compañeros de trabajo o desayunar con ellos. Dame algo de leer en papel, periódico o libro, que ya me entretengo yo. Si eres de los que necesitan de vez en cuando parar para hablar con alguien puede que esta vida no sea para ti.


Después de tanto tiempo, puedo recopilar una lista de consejos a aplicar en la vida diaria para alguien que trabaja desde casa. Consejos que yo no cumplo al 100%, prueba es que son las 19:51 y llevo trabajando desde las 8:15. Mal, Ignacio, mal.

1. Mantén una rutina

Levántate más o menos a la misma hora todos los días. Cuando pase un tiempo no vas a necesitar el despertador, así que tu corazón no va a sufrir oyendo ese pitido del demonio. Yo hago trampa: Me levanto a la misma hora que mi mujer se va a trabajar y le hago el desayuno: Yo contento, ella contenta. Esto es un win-win en toda regla.

2. Recoge la casa

No hay nada peor que trabajar en un sitio lleno de calcetines por el suelo y los restos de la cena del día anterior. Recoge un poco cuando te levantes, te hará sentir mejor y luego no tendrás que hacerlo, que da mucha pereza al terminar de trabajar.

3. Organiza tus tareas del día

Al inicio de la jornada, agarro mi agenda de papel y apunto las tareas que tengo que ir haciendo durante el día. No hay que volverse loco con cumplirlas todas porque a veces no es posible pero el hecho de escribirlas te hace sentir responsable de ellas.

Creo que es mejor empezar respondiendo emails que puedas hacer rápido. A continuación, haz las tareas que no tengas ganas de hacer. Así, poco antes y después de comer te quedan las que te gustan más, justo cuando corres peligro de decaer en tu jornada.

4. Haz ejercicio

¿ Te aburre el gimnasio? Apúntate a Pilates o Boxeo o alguna otra actividad guiada. Yo he sido un malísimo deportista siempre. Era de los últimos elegidos para jugar a cualquier cosa así que no soy el mejor para dar consejos pero no queda otra. ¿Quieres engañarte a ti mismo? Sube las escaleras de tu primer piso y créete que ya has hecho ejercicio.

Suda, no hay otra solución. Los primeros días son horribles pero luego te lo empieza a pedir el cuerpo.

5. Invierte en elementos de tu estudio que te hagan sentir cómodo

Una buena lámpara con luz cálida, cuelga unos cuadros con un poquito de sentido estético. No vayas por ahí colgando pósters de chicas dándose el lote, es de mal gusto, feo y machista.

6. Lee en papel o tinta electrónica

Difícil, ¿Eh? Descansa los ojos de tanta iluminación y siéntate a leer algo. Coge un libro que no tenga nada que ver (si programas en PHP no vale un libro de JavaScript), ciencia ficción, ensayo, cómic, lo que sea pero lee algo distinto en una no-pantalla-retroiluminada.

7. Apaga a alguna hora

Tienes que terminar en algún momento. En serio.

8. Aprende a cocinar

Apúntate a algún curso y empieza a alimentarte mejor. Lee sobre cocina y aprende nuevos platos, es un entretenimiento bonito y útil. Pon música de fondo y pelarás cebollas silbando.

9. Trabaja en otro sitio de vez en cuando

Paga por algún coworking o vete a la oficina de alguien a trabajar de vez en cuando. No es bueno estar todos los días en el mismo sitio encerrado.

Una de las cosas que no me gusta de trabajar en casa es que te vuelves obsesivo con los ruidos del edificio (si trabajas en un piso). Sé a qué hora limpia mi vecina y a cuándo empieza mi vecino a hacer sus cosas. Los ruidos que se repiten día a día a la misma hora acaban por molestarte. En ese momento es mejor cambiar de ambiente por unos días.

10. Paga herramientas que te liberen de papeleo tedioso

Yo uso Freshbooks y también pago mensualmente a una asesoría para que me lleve los papeles de autónomo. No sólo dejarás de hacer cosas que odias sino que puedes aprovechar ese tiempo para lo que quieras. Para un autónomo, el tiempo es dinero o felicidad.

11. Distráete un poco

No se puede trabajar al 100% todo el tiempo. Si llevas mucho tiempo con una tarea y piensas “un poquito más”, es hora de parar, quitarte el pijama, ponerte unos pantalones y baja al parque a sentarte en un banco u observar alguna obra.

12. Duerme bien

Haz la prueba, acuéstate pronto un día y verás que al día siguiente el rendimiento es muy distinto. Si no has dormido bien, echa un sueñecito a la hora de la siesta. Si hay ruido, ponte tapones. 10 minutos es más que suficiente.

13. Intenta no pensar en todo lo que tienes que hacer cuando te tomas el día libre

SIEMPRE hay cosas que hacer.

 

 

He grabado un curso en Domestika y aquí cuento la experiencia

La gente de Domestika es muy profesional, dejémoslo claro.

Básicamente hay tres fases durante la grabación del curso:

En la primera hablan un poco contigo, te conocen y te dan un montón de consejos para grabar las cosas y que no te pongas nervioso. Son gente muy simpática que te hacen la vida fácil. Siendo desarrollador me sorprendió gratamente el nivel de automatización que tienen para muchas de las cosas. Recibes emails bien escalados en el tiempo en los que te cuentan lo que tienes que hacer. Nada de un solo email con montones de datos e información. Cada cosa va llegando a su debido momento.

En la segunda comienzas a grabar los screencasts. En mi caso recién salía de una gripazo y encima soy fumador por lo que tardo en curarme. Durante los screencasts no paro de toser y echar gargajos (lo siento por el editor de Domestika) pero el talento de ellos lo compensa. No sé cómo lo hacen pero emplean una especie de cirugía plástica en los vídeos que hacen que mi voz pase de darme auténtico asco a darme simplemente pena y sin toses ni interrupciones. ¡Un trabajazo!

¿Escenario? Todo mentira

En la tercera te llevan a un sitio de grabación que casualmente estaba debajo de mi casa (30 segundos entre portal y portal). El que vive en Madrid puede comprender la alegría que supone no restregarte en el metro durante un par de días cuando trabajas en casa por norma general.

Durante dos días me reúno con ellos en el sitio para grabar (el tráiler y las entradas y salidas de los screencasts). Todo fue bastante fluido la verdad, pensaba que tendría más problemas o más interrupciones pero en general salió todo bien entre otras cosas porque trabajar con los chicos de Domestika es extremadamente fácil. Durante el rodaje nos reímos bastante y el ambiente era relajado, lo cual hizo las cosas más sencillas.

La gente de Domestika con sus cosas

Cuando te tiras horas y horas hablando sin parar a cámara y llegas a tu casa no llegas cansado, no, llegas y sigues hablando, con quien sea: tu mujer, tu perro o al espejo. Sólo quieres seguir soltando tus cosas a todo tren.

El día que sale el tráiler te deja loquísimo verte hacer cucamonas. La horrible sensación de escucharme y hacer el chorra hizo que sintiera cierta decepción al principio pero me di cuenta de que tú no puedes opinar sobre tu propio vídeo. Cuando la gente que me conoce empezó a decir que no había nada raro y que el vídeo estaba bien me quedé más tranquilo. Ahora lo veo y me pregunto qué es lo que hace esta gente para que el vídeo quede tan chulérrimo.

Parece que el curso está teniendo aceptación así que estoy contento. Los foros empiezan a tener actividad con preguntas de la gente y algún problema técnico que otro pero la cosa va muy bien.

¡Gracias a Domestika y a la gente que me acompañó en la grabación!

También tengo que agradecer a Siteground porque me dejaron un hosting para las pruebas durante la grabación y que conste que durante el curso no hablo mejor ni peor de ellos que de otros.

Si queréis saber algo más sobre el curso aquí lo tenéis: http://www.domestika.org/es/courses/112-creacion-de-una-web-profesional-con-wordpress/igmoweb