Tracking de Instalaciones en Apps

A la hora de elegir un sistema de rastreo, uno de los trackers, hemos de tener en cuenta, entre otras cosas, qué método van a utilizar a la hora de decidir cuál es la identificación del dispositivo. Al no existir un estándar entre las distintas plataformas, dependiendo del sistema operativo o de la storepodemos tener mayor facilidad para saber qué dispositivo único (parecido a los usuarios únicos en web) tenemos delante.

Device Fingerprint

Este sistema anónimo intenta detectar una serie de eventos en los que haya una alta probabilidad de concordancia. En base a estos elementos, podemos llegar a interpretar que si una persona pulsa un anuncio y un poco después se instala una aplicación, es el mismo dispsitivo el que ha realizado dicha instalación. Algunos datos pueden ser la IP, la fecha, el navegador, etc…

Este proceso es completamente transparente para el usuario y tárda unas décimas de segundo en procesarse, por lo que es poco probable que ningún sistema cierre esta forma de trabajar. Pero esto puede generar algunos duplicados o falsas huellas, ya que se pueden generar algunas discrepancias. la fiabilidad ronda el 95%.

UDID (obsoleto), IFA e IFV

Aunque el UDID (Identificador único de dispositivo) de Apple era el sistema para saber exactamente qué dispositivo teníamos entre manos, siendo un identificador único y por tanto fiable, este sistema llegó a un proceso de falta de privacidad altamente preocupante por lo que quedó obsoleto. Para ello Apple se sacó de la manga el IFA (identificador de la publicidad) que no es permanente, no es personal y las Apps tienen acceso a él de forma libre. De una forma similar tenemos el IFV (identificador de proveedor) para detectar aquellas Apps que ya vienen con el dispositivo o son Apps que incorpora la propia operadora de serie. Hay que tener presente que este identificador sólo funciona en iOS y que está previsto que en iOS7 se incorpore una opciónd e opt-out, para que no pueda ser utilizado.

Cookie Tracking

Es un sistema planteado para Safari en iOS y es similar al de las cookies tradicionales de cualquier navegador. Este sistema básicamente lo que permitía es que, al abrir un enlace de una App desde Safari se pasaba esta cookie a la App, pero esa era su completa limitación. Actualmente no es lo que más se utilice debido a su gran limitación y a la entrada de otros navegadores en iOS.

Android Referrer

Este es, como su nombre indica, el sistema elegido por el propio Google para Android. Es una evolución de Google Analytics y básicamente permite que Google Play recoja los parámetros tradicionales (UTM) y se hagan llegar a la propia App. pero, como su nombre indica y comento, sólo es válido para Android.

OpenUDID

Esta es la aplicación que plantea la comunidad libre, de uso gratuito y que pemite el paso de este identificador entre aplicaciones, de forma que sólo se genera un único código por dispositivo. Vendría a ser la idea de sustitución del UDID. Este sistema tiene la opción de opt-out y parece ser la alternativa óptima en estos momentos.

MAC Address

La dirección MAC (Media Access Control) es la herramienta que históricamente se ha utilizado para identificar las tarjetas de red en cualquier dispositivos. Este identificador es único por hardware y en general su uso va mediante encriptación. De la misma forma que pasaba con el UDID, este identificador no se puede cambiar, por lo que aunque el 100% fiable no permite una protección de privacidad.

ODIN

El ODIN (Open Device Identifier Number) tiene la misma filosofía del OpenUDID pero con la diferencia de que se plantea como un identificador multi dispositivo, de forma que, por decirlo de alguna manera, identifica un usuario pero de forma anónima al dispositivo. Este identificador es válido en todas las plataformas (iOS, Android, Windows Mobile…) pero no está, actualmente, muy en mente de los desarrolladores, por lo que tiene un bajo uso.

Aunque estos son los sistemas abiertos o cerrados más utilizados, existen otros tantos, principalmente proporcionados por plataformas publicitarias, pero que no están profundizando tanto como lo están haciendo estos anteriormente mencionados.

Analítica móvil

Según van pasando los días en Geenapp y recibimos solicitudes de información de cómo promocionar una App en nuestra plataforma muchos desarrolladores quieren saber cómo hacemos para medir. Y ese es el elemento básico y el secreto de la promoción de cualquier App: la analítica móvil. El ejemplo claro y sencillo, para los que hayáis tenido un sitio web es el de poner siempre Google Analytics. Es quizá la forma más sencilla de medir la información de un sitio web. ¿Por qué no hacer exactamente lo mismo con una App? Sí, se puede. En Geenapp estamos integrados con las mayores plataformas de medición que además nos ayudan a, entre otras cosas, poder medir las instalaciones nuevas realizadas en la App. ¿Y cuáles son estas plataformas de analítica? Tenemos, por ejemplo, las siguientes:

Cada una de estas plataformas funciona a su manera, unos te cobran por evento, otros te dan el servicio gratis, otros te cobran por petición recibida… Lo importante es que estas herramientas te dan un panel de control en el que poder ver el uso de la App, los nuevos usuarios / instalaciones, el engagement, qué secciones de la App son las más visitadas, qué acciones son las que más utilizan los usuarios. Además, si vas a promocionar, de cualquier manera, tu App, es básico saber qué fuentes son las que te generan el mayor tráfico, conversiones, instalaciones y, en definitiva, dónde conseguir los mejores usuarios para una mayor conversión.

WordPress con Integridad Relacional

WordPress por defecto suele venir preparado para una base de datos en MySQL con su sistema de almacenamiento en myISAM. Pero este sistema no tiene integridad referencial. Esto puede llegar a implicar que la velocidad a la hora de relacionar los campos de tablas distintas no acaba de ser el que debería, y hay una posibilidad de mejorarlo con innoDB.

Con el siguiente script se puede convertir la base de datos a este sistema:

ALTER TABLE cb_commentmeta ENGINE=InnoDB;
ALTER TABLE cb_comments ENGINE=InnoDB;
ALTER TABLE cb_links ENGINE=InnoDB;
ALTER TABLE cb_options ENGINE=InnoDB;
ALTER TABLE cb_postmeta ENGINE=InnoDB;
ALTER TABLE cb_posts ENGINE=InnoDB;
ALTER TABLE cb_terms ENGINE=InnoDB;
ALTER TABLE cb_term_relationships ENGINE=InnoDB;
ALTER TABLE cb_term_taxonomy ENGINE=InnoDB;
ALTER TABLE cb_usermeta ENGINE=InnoDB;
ALTER TABLE cb_users ENGINE=InnoDB;

ALTER TABLE cb_comments ADD INDEX ( user_id ) ;
ALTER TABLE cb_links ADD INDEX ( link_owner ) ;
ALTER TABLE cb_posts ADD INDEX ( guid ) ;
ALTER TABLE cb_posts ADD INDEX ( post_date ) ;
ALTER TABLE cb_term_taxonomy ADD INDEX ( term_id ) ;
ALTER TABLE cb_term_taxonomy ADD INDEX ( parent ) ;
ALTER TABLE cb_users ADD INDEX ( user_email ) ;

UPDATE cb_term_taxonomy SET term_id=NULL WHERE term_id=0;
UPDATE cb_term_relationships SET term_taxonomy_id=NULL WHERE term_taxonomy_id=0;
UPDATE cb_term_taxonomy SET parent=NULL WHERE parent=0;
UPDATE cb_commentmeta SET comment_id=NULL WHERE comment_id=0;
UPDATE cb_links SET link_owner=NULL;
UPDATE cb_postmeta SET post_id=NULL WHERE post_id=0;
UPDATE cb_usermeta SET user_id=NULL WHERE user_id=0;
UPDATE cb_comments SET comment_post_ID=NULL WHERE comment_post_ID=0;
UPDATE cb_comments SET user_id=NULL WHERE user_id=0;
UPDATE cb_comments SET comment_parent=NULL WHERE comment_parent=0;
UPDATE cb_posts SET post_author=NULL WHERE post_author=0;

ALTER TABLE cb_term_taxonomy CHANGE term_id term_id BIGINT( 20 ) UNSIGNED NULL DEFAULT NULL ;
ALTER TABLE cb_term_relationships CHANGE term_taxonomy_id term_taxonomy_id BIGINT( 20 ) UNSIGNED NULL DEFAULT NULL ;
ALTER TABLE cb_term_taxonomy CHANGE parent parent BIGINT( 20 ) UNSIGNED NULL DEFAULT NULL ;
ALTER TABLE cb_commentmeta CHANGE comment_id comment_id BIGINT( 20 ) UNSIGNED NULL DEFAULT NULL ;
ALTER TABLE cb_links CHANGE link_owner link_owner BIGINT( 20 ) UNSIGNED NULL DEFAULT NULL ;
ALTER TABLE cb_postmeta CHANGE post_id post_id BIGINT( 20 ) UNSIGNED NULL DEFAULT NULL ;
ALTER TABLE cb_usermeta CHANGE user_id user_id BIGINT( 20 ) UNSIGNED NULL DEFAULT NULL ;
ALTER TABLE cb_comments CHANGE comment_post_ID comment_post_ID BIGINT( 20 ) UNSIGNED NULL DEFAULT NULL ;
ALTER TABLE cb_comments CHANGE user_id user_id BIGINT( 20 ) UNSIGNED NULL DEFAULT NULL ;
ALTER TABLE cb_comments CHANGE comment_parent comment_parent BIGINT( 20 ) UNSIGNED NULL DEFAULT NULL ;
ALTER TABLE cb_posts CHANGE post_author post_author BIGINT( 20 ) UNSIGNED NULL DEFAULT NULL ;

ALTER TABLE cb_links ADD FOREIGN KEY ( link_owner ) REFERENCES cb_users (ID) ON DELETE RESTRICT ON UPDATE  RESTRICT ;
ALTER TABLE cb_term_taxonomy ADD FOREIGN KEY ( term_id ) REFERENCES cb_terms (term_id) ON DELETE RESTRICT ON UPDATE  RESTRICT ;
ALTER TABLE cb_term_relationships ADD FOREIGN KEY ( term_taxonomy_id ) REFERENCES cb_term_taxonomy (term_taxonomy_id) ON DELETE RESTRICT ON UPDATE  RESTRICT ;
--ALTER TABLE cb_term_taxonomy ADD FOREIGN KEY ( parent ) REFERENCES cb_term_taxonomy (term_taxonomy_id) ON DELETE RESTRICT ON UPDATE  RESTRICT ;
ALTER TABLE cb_usermeta ADD FOREIGN KEY ( user_id ) REFERENCES cb_users (ID) ON DELETE RESTRICT ON UPDATE  RESTRICT ;
ALTER TABLE cb_postmeta ADD FOREIGN KEY ( post_id ) REFERENCES cb_posts (ID) ON DELETE RESTRICT ON UPDATE  RESTRICT ;
ALTER TABLE cb_commentmeta ADD FOREIGN KEY ( comment_id ) REFERENCES cb_comments (comment_ID) ON DELETE RESTRICT ON UPDATE  RESTRICT  ;
ALTER TABLE cb_comments ADD FOREIGN KEY ( comment_post_ID ) REFERENCES cb_posts (ID) ON DELETE RESTRICT ON UPDATE  RESTRICT ;
--ALTER TABLE cb_comments ADD FOREIGN KEY ( comment_parent ) REFERENCES cb_comments (comment_ID) ON DELETE RESTRICT ON UPDATE  RESTRICT ;
--ALTER TABLE cb_comments ADD FOREIGN KEY ( user_id ) REFERENCES cb_users (ID) ON DELETE RESTRICT ON UPDATE  RESTRICT ;

De todas formas, si aplicamos esto, debido a que WordPress no stá bien desarrollado, hay dos elementos que no se pueden relacionar, sino el sistema deja de funcionar, que son las relaciones de etiquetas con entradas, y de los comentarios.

Eso significa que las consultas marcadas como comentarios no deben ejecutarse a menos que se haga un pequeño hackeo del código fuente del propio WordPress para eliminar esta incompatibilidad.

Bloquear un robot de rastreo / buscador

Hay varias formas de bloquear la aparición de páginas en los resultados de búsqueda, pero no todas ellas sirven para lo mismo. Y todo viene porque hacemos un mal uso de las palabras [rastrear] e [indexar].

En base a todo esto hay que diferenciar varias opciones: bloquear por robots.txt, usar el meta-noindex (y su respectiva cabecera HTTP), usar el rel-nofollow

El sistema de bloqueo por robots.txt es el más restrictivo. La idea es que un robot se encuentre en una especie de pasillo y haya puertas a su alrededor. El robot sabe que hay puertas, pero en este caso estas puertas están tapiadas. El robot podría llegar a saber qué hay detrás de esas puertas porque otras puertas o gente de otros pasillos le dicen lo que hay, pero no puede entrar a comprobarlo porque para él esa puerta está tapiada. Esto, en resumen, es que si uno (o varios) elementos están bloqueados por Disallowno deben tenerse en cuenta en absoluto para nada a la hora de organizar los resultados.

El uso del meta-robots (o su cabecera HTTP, que hace exactamente lo mismo) tiene otro objetivo. Siguiendo con el ejemplo de las puertas, esta puerta está disponible para entrar, chafardear pero el robot no le puede decir a nadie lo que ha visto dentro de esa habitación. La diferencia con el punto anterior es que, en este caso el robot sí que conoce lo que hay dentro y lo puede utilizar a la hora de ordenar los resultados, pero con una condición: no le puede decir a nadie lo que hay. Esto significa que se puede rastrear el contenido, que se puede usar a tener en cuenta a la hora de generar el índice pero no puede estar en el índice. Por lo tanto, los elementos con noindexhan de estar bien pensados porque sí que afectan a SEO (aunque no se vean en los SERP).

Para acabar, con respecto al rel-nofollowme gustaría dejar claro que los robots sí que siguen estos enlaces (si quieren) y que, en este caso, son ellos los que deciden qué peso darles. Esto viene por lo que el estándar dice y no lo que Google dice:

The nofollow keyword indicates that the link is not endorsed by the original author or publisher of the page, or that the link to the referenced document was included primarily because of a commercial relationship between people affiliated with the two pages.

Como bien dice el texto, el rel-nofollowsignifica que el enlace de destino no tiene que ver con el autor original del artículo o del soporte o que se ha incluido como parte de una relación comercial entre las dos páginas. En ningún caso indica que los enlaces no se tengan que seguir.

En este último caso no se puede confundir con el meta-nofollow. En este caso sí que los robots deberían no seguir los enlaces que hay en toda esa página:

The NOFOLLOW directive only applies to links on this page. It’s entirely likely that a robot might find the same links on some other page without a NOFOLLOW (perhaps on some other site), and so still arrives at your undesired page.

Para acabar, algunos buscadores (como Google) tienen en sus herramientas para webmasters una zona en la que poder “sacar” determinadas páginas de los resultados. Hay que ener en cuenta que un buscador no puede eliminar contenidos de su índice a menos que esté bloqueado anteriormente, y esta es la razón por la que antes de eliminar nada te solicita que esté bloqueado el contenido o que de un código de error 4xx. Si se cumple esto (para que en un siguiente rastreo no se añada el contenido) se realiza un trabajo que, una vez listados los resultados de búsqueda se filtran estos contenidos que se le han indicado para que no aparezcan, aunque, se podría decir, que es “un apaño” temporal hasta la siguiente actualización del índice.

ARPANET y el origen de Internet

¿Tienes presente que “Internet” comenzó a gestarse en 1967 y que se puso “en línea” en 1969? Estas últimas semanas he tenido la oportunidad de revisar documentos oficiales y, por curiosidad, comencé a mirar la primera documentación que hubiera sobre Internet… pero, en realidad fui tirando para atrás y, al final, en el RFC 8 [ARPA Network Functional Specifications. G. Deloche. May 1969. (Status: UNKNOWN)] se habla de él…

Es curioso porque este documento no es muy sencillo de encontrar, pero buscando y buscando he conseguido una copia de ese RFC 8. Lo entretenido del documento es que no se entiende prácticamente nada y que sólo la primera página (la portada) está hecha a máquina de escribir. 7 páginas escritas y 2 de un diagrama es la base de Internet, iniciado todo por una petición del Departamento de Defensa de los USA. Gerard Deloche es el redactor de dicho documento, trabajando en UCLA, el 2º nodo de la red de redes el 21 de noviembre de 1969.

Unos años después, en diciembre de 1974, un señor llamado Vinton Cerf (este seguramente os suene algo más) publicaba la primera especificación de una cosa llamada “Internet”, el RFC 675 [Specification of Internet Transmission Control Program. December 1974. (Status: UNKNOWN)]. Que conste que el TCP se preparó antes, pero la especificación “final” apareció con ese documento. Y hay que tener en cuenta que esto sólo explica cómo transportar los paquetes, la información, pero no habla todavía de las direcciones IP; es el RFC 791 [Internet Protocol. J. Postel. September 1981. (Status: STANDARD)], entrada basada en las 6 versiones anteriores existentes del IP de DARPA.

This document specifies the DoD Standard Internet Protocol. This document is based on six earlier editions of the ARPA Internet Protocol Specification, and the present text draws heavily from them. There have been many contributors to this work both in terms of concepts and in terms of text. This edition revises aspects of addressing, error handling, option codes, and the security, precedence, compartments, and handling restriction features of the internet protocol.

Eso sí, mucho protocolo, mucho sistema de transporte pero hasta que el 1989 no se acabaron los OSI para el TCP/IP y que Tim Berners-Lee se inventase el HTML, el primer navegador (llamado WorldWideWeb) y se pusiera en marcha el primer servidor web en un Next (sí, esos ordenadores que fabricó Steve Jobs cuando lo echaron de Apple).

Además, hay un detalle que, si me paro a pensarlo fríamente es muy fuerte. Hasta 1993 el gobierno de Estados Unidos tenía como mandatario que Internet no podía tener un concepto comercial, sólo de comunicación académica, científica y gubernamental. Esto da mucho a pensar de los primeros buscadores, los primeros sitios web y que yo me comenzase a conectar en 1994 de tanto en tanto…

Hay mucha documentación en la red de redes sobre los comienzos de Internet, pero, la verdad, tras unas conversaciones con Xavier (compañero en el Postgrado Web Analytics) que colabora con el CERN, donde se cocinó y coció lo que hoy me da de comer, creo que valía la pena simplemente hacer un pequeño homenaje a todo esto tan grande que se ha creado prácticamente de la nada.

Los DNAME en las DNS

Aunque ahora mismo es tan sólo una propuesta, creo muy acertada esta nueva posible entrada de las DNS porque, sobretodo a nivel de rendimiento de WPO podría dar un salto cualitativo en cuanto a determinadas acciones que hacemos habitualmente con los dominios, más concretamente con las redirecciones. Incluso, he de añadir, para reducir el impacto de la cantidad de líneas que puede haber en los servidores DNS.

Para situarnos estoy hablando de la propuesta del RFC 6672(DNAME Redirection in the DNS) que propone incorporar una entrada nueva llamada DNAME.

Para no entrar en detalles muy raros, voy a intentar poner un caso para ver el sentido que tiene. Imaginad que tenemos dos dominios iguales, con las mismas entradas DNS. Por ejemplo [example.com] y [dominio.es]. Dado este caso, en que los dos dominios son exactamente iguales (a nivel DNS)… ¿tiene sentido mantener dos copias de las entradas DNS? ¿No sería más fácil decir que las entradas DNS de [dominio.es] son una copia de las de [example.com] y simplemente cambiando las del .com que se actualizase todo?

Pues básicamente este es el objetivo de la entrada DNAME. El ejemplo visual (los que tocáis mucho las DNS seguramente lo pilléis enseguida:

    QNAME            owner  DNAME   target         result
    ---------------- -------------- -------------- -----------------
    com.             example.com.   example.net.   <no match>
    example.com.     example.com.   example.net.   [0]
    a.example.com.   example.com.   example.net.   a.example.net.
    a.b.example.com. example.com.   example.net.   a.b.example.net.
    ab.example.com.  b.example.com. example.net.   <no match>
    foo.example.com. example.com.   example.net.   foo.example.net.
    a.x.example.com. x.example.com. example.net.   a.example.net.
    a.example.com.   example.com.   y.example.net. a.y.example.net.
    cyc.example.com. example.com.   example.com.   cyc.example.com.
    cyc.example.com. example.com.   c.example.com. cyc.c.example.com.
    shortloop.x.x.   x.             .              shortloop.x.
    shortloop.x.     x.             .              shortloop.

El objetivo es que el campo “target” sea como el sustituto del patrón que se le pasa. De esta forma, poniendo la tercera línea de ejemplo, tendríamos que, partiendo de la base de [a.example.com] el dominio sería [example.com] y el DNAME sería [example.net], si hacemos un “sustituir” de [example.net] por [example.com] nos quedaría [a.example.net].

El planteamiento, a nivel de similitud, es como un CNAME con esteroides, ya que no deja de ser como un alias, pero que además sustituye fragmentos de las entradas DNS por otras que pueden ser de otro dominio.

Un detalle interesante es que, aunque no se recomienda su uso, se podría a llegar a utilizar el “wildcard” (o sea, el [*.example.com] para sustituir grandes cantidades de entradas DNS por otras. No se recomienda el uso porque podría invalidar el DNSSEC, pero la verdad, teniendo en cuenta la poca penetración que tiene, tampoco tengo claro que, para la mayoría, sea un problema.

Aunque no deja de ser una propuesta (en mi opinión muy interesante) no tengo claro que sea algo que se vaya a implementar rápidamente. Seguramente dependerá más de los ISP que comiencen a implementar servidores que lo soporten, pero, tampoco es algo que creo que sea muy recomendable para la gran mayoría de los usuarios, ya que un pequeño error puede provocar la invalidación de las DNS. Así que, lo más probable es que para añadir una entrada de este tipo se tengan que hacer varias validaciones “automáticas” para controlar las posibles cagadas poniendo estas entradas.

Dominios reservados

¿Cuál es el dominio que no existe y que deberíamos usar siempre que hacemos referencia a una dirección URI que no existe? Pues hay varios, no os lo voy a negar, y todo depende de las necesidades que tengamos.

Y es que existe el RFC 2606 que habla de esto mismo… los Reserved Top Level DNS Names. Básicamente este documento nos informa de los 4 TLD que hay cuando queremos hacer referencia a pruebas.

  • .test: Se recomienda para probar DNS.
  • .example: Se recomienda cuando en un documento se hace referencia a alguna dirección.
  • .invalid: Se recomienda cuando se hace referencia a dominios incorrectos o errores.
  • .localhost: Este es el único que técnicamente no es del todo un error o un ejemplo, ya que se puede utilizar internamente en las DNS para hacer una autollamada o hacer uso de direcciones IP privadas sobre él.

Claro está, esto es siempre para los TLD, pero ¿qué ocurre en los segundos nivele? Vamos, en lo que normalmente conocemos como un “dominio”? Para ello el sistema es claro: example.com, example.net y example.org.

Hay otros TLD de los nuevos que, ya de base, llevan una serie de limitaciones. Por ejemplo el .INFO define el dominio [example.info] como un dominio .info reservado en este caso para la IANA. Esto mismo ocurre con los dominios .biz reservadosque excluyen el [example.biz]. En principio, el resto de dominios, como desde hace tiempo, son asignados y aprobados por IANA, ocurre lo mismo.

En el caso de los ccTLD no se especifica nada a nivel general, sino que el bloqueo de los dominios queda en manos de cada uno de los organismos. Por ejemplo, en NIC.ES, el organismo que regula los dominios “.es”, quedan prohibido según su documentación el [dominio.es]. Hay otros tantos, pero este parece ser el único que el organismo no usará (ya que aunque está prohibido, el [dominio.es] sí que lo utilizan como promoción, saltándose sus propias reglas (como decenas de veces han hecho en e pasado).

En otros casos, como por ejemplo el dominio francés .FR (y todos los que gestiona el organismo) no plantea un dominio de segundo nivel reservado para este uso. Sí que es cierto que disponen de varios dominios reservados, pero concretamente para hacerse eco de un ejemplo de uso no.

Así que a partir de ahora, si vas a escribir una entrada hablando de dominios de ejemplo, o tienes que referirte a ellos, ya sabes que has de analizar de forma diferente lo general de los dominios territoriales.

Recomendaciones de Google cuando se va a programar en HTML

Google genera mucho contenido de código abierto, y entre este se encuentra muchísmo código de programación. Pues existen una serie de guíasen las que se recomiendan determinadas formas de trabajar que pueden ser interesantes, principalmente (al menos a mi) las que hacen referencia al HTML. Me gustaría destacar algunas de las recomendaciones… que no significa que yo las use o que esté de acuerdo, pero creo que son mencionables.

Uso del protocolo

No se recomienda indicar el uso del protocolo en cuestión cuandos e llama a un objeto. A mi me gusta ponerlo, y aunque sé que en el RFC se dice que no es necesario…

<!-- No recomendado -->
<script src="http://www.example.com/example.js"></script>
<!-- Sí recomendado -->
<script src="//www.example.com/example.js"></script>

Indentación

Algo que yo suelo hacer… que el código esté bien ordenado. Para ello las “tabulaciones” se indicarán con 2 espacios (se recomienda no usar tabulaciones, aunque yo es lo que uso).

<ul>
  <li>Fantastic</li>
  <li>Great</li>
</ul>

Mayúsculas/Minúsculas

Se recomienda que todo el HTML esté en minúculas:

<!-- No recomendado -->
<A HREF="/">Home</A>
<!-- Sí recomendado -->
<img src="example.png" alt="Google">

Espacios en blanco

Es mejor no dejar espacios en blanco si no son necesarios.

<!-- No recomendado -->
<p>¿Qué? </p>
<!-- Sí recomendado -->
<p>Gracias</p>

Codificación

Esto es muy sencillo… se recomienda el uso de UTF-8 (sin BOM). Además, en las plantillas HTML se debe indicar la meta-etiqueta correspondiente:

<meta charset="utf-8">

HTML5

Se prefiere HTML5 en los documentos, con su cabecera correspondiente:

<!DOCTYPE html>

Esto también incluye el uso del MIME text/html y no de XHTML y, por ello, no hace falta cerrar las etiquetas o sea, es mejor <br> y no <br />.

Código HTML válidado

Algo de lo que siempre hay muchas discusiones… personalmente es lgo que me gusta cumplir, al menos cuando la web no tiene códigos de publicidad u otros elementos externos.

<!-- No recomendado -->
<title>Test</title>
<article>This is only a test.
<!-- Sí recomendado -->
<!DOCTYPE html>
<meta charset="utf-8">
<title>Test</title>
<article>This is only a test.</article>

Semántica

Hay que usar el HTML según su valor inicial, esdecir, un P es un párrafo, y un A un enlace.

<!-- No recomendado -->
<div onclick="visitarRecomendados();">Recomendados</div>
<!-- Sí recomendado -->
<a href="/recomendados/">Recomendados</a>

Multimedia

Hay que proveer de contenido alternativo en el caso de uso de elementos multimedia. Por ejemplo, las imágenes deberían llevar un texto alternativo.

<!-- No recomendado -->
<img src="example.png">
<!-- Sí recomendado -->
<img src="example.png" alt="Contenido de ejemplo.">

Inter dependencia

Hay que intentar mantener diferenciado y desvinculado el código de la página, de la estructura (markup) de la presentación (styling) del comportamiento con los mismos (scripting).

Evitar entidades

Gracias al UTF-8, es casi innecesario el uso de entidades HTML (por ejemplo el &eur para representar ). Sólo hay dos excepciones habituales que son el & y el < o >.

<!-- No recomendado -->
El símbolos del Euro es: &ldquo;&eur;&rdquo;.
<!-- Sí recomendado -->
El símbolos del Euro es: “€”.

Etiquetas opcionales

Este es otro de esos puntos en los que no estoy 100% de acuerdo. Si bien es cierto qu una de las grandísimas ventajas del HTML5 es que no es necesario escribir todo el código estructurado como hasta ahora, no tengo muy claro que sea interesante de cara a la compatibilidad con todo.

<!-- No recomendado -->
<!DOCTYPE html>
<html>
  <head>
    <title>gastando bytes</title>
  </head>
  <body>
    <p>Mal.</p>
  </body>
</html>
<!-- Sí recomendado -->
<!DOCTYPE html>
<title>ahorrando bytes</title>
<p>Bien.

Atributo “type”

En cambio, esta sí que la considero del todo útil (ya que antes me arecía completamente inútil). En principio los ficheros externos a los que llamamos (por ejemplo .CC o .JS) no es necesarios indicarles el MIME al que mandamos (al fin y al cabo, los ficheros ya lo indican per sé).

<!-- No recomendado -->
<link rel="stylesheet" href="//www.google.com/css/maia.css" type="text/css">
<!-- Sí recomendado -->
<link rel="stylesheet" href="//www.google.com/css/maia.css">
<!-- No recomendado -->
<script src="//www.google.com/js/gweb/analytics/autotrack.js" type="text/javascript"></script>
<!-- Sí recomendado -->
<script src="//www.google.com/js/gweb/analytics/autotrack.js"></script>

Formateado general

Hay que usar un salto de línea para aquellos bloques, listas o tablas e indentar cada elemento hijo. Esta es otra de las recomendaciones que agradezco, porque veo programadores que han hecho mucho daño al HTML.

<blockquote>
  <p><em>prueba</em> de un texto cualquiera.</p>
</blockquote>
<ul>
  <li>José
  <li>María
  <li>Juan
</ul>
<table>
  <thead>
    <tr>
      <th scope="col">Ingresos
      <th scope="col">Gastos
  <tbody>
    <tr>
      <td>5,00 €
      <td>4,50 €
</table>

Uso de comillas

Se recomienda el uso de comillas dobles en vez de comilla simple para los atributos.

<!-- No recomendado -->
<a class='boton boton-alternativo'>Acceder</a>
<!-- Sí recomendado -->
<a class="boton boton-alternativo">Acceder</a>

También hay una serie de recomendaciones para las hojas de estilo CSS. A parte de que el CSS debería validar (algo lógico). Además, se recomeinda que el nombre de las clases sea corto y genérico. Por ejemplo, es más recomendable usar #nav que #navegacion o usar .aux que no .boton-verde.

Selectores

Además, por un tema de rendimiento (muy importante de cara al WPO) hay que intentar ir al elemento más concreto que incliur los generales. Yo principalmente lo veo claro con los ID, pero no siempre con las clases.

/* No recomendado */
ul#ejemplo {...}
div.error {...}
/* Sí recomendado */
#ejemplo {...}
.error {...}

Propiedades cortas

Algunos elementos permiten propiedades agregadas…

/* No recomendado */
border-top-style: none;
font-family: palatino, georgia, serif;
font-size: 100%;
line-height: 1.6;
padding-bottom: 2em;
padding-left: 1em;
padding-right: 1em;
padding-top: 0;
/* Sí recomendado */
border-top: 0;
font: 100%/1.6 palatino, georgia, serif;
padding: 0 1em 2em;

Valores 0

Los datos que son de valor 0 no requieren de unidades para acompañarlo. De la misma forma, si un vaor va entre -1 y 1, no es necesario indicar el 0.

margin: 0;
padding: 0;
font-size: .8em;

Hexadecimal

Hay que intentar usar los colores cuanto más cortos mejor. De esta forma, si hay colores que se pueden reducir a 3 caracteres, mejor.

/* No recomendado */
color: #eebbcc;
/* Sí recomendado */
color: #ebc;

Ordenar los elementos

Se recomienda ordenar los elementos de forma alfabética. Claro está dentro de cada elemento.

background: fuchsia;
border: 1px solid;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
color: black;
text-align: center;
text-indent: 2em;

Finalizar las declaraciones

Al final de cada uno de los elementos se recomienda finalizar con un punto y coma.

/* No recomendado */
.test {
  display: block;
  height: 100px
}
/* Sí recomendado */
.test {
  display: block;
  height: 100px;
}

Separar propiedades y valores

Siempre utilizar un espacio entre las distintas propiedades y sus valores, pero no entre el valor y el punto y coma final.

/* No recomendado */
h3 {
  font-weight:bold;
}
/* Sí recomendado */
h3 {
  font-weight: bold;
}

Selectores y declaraciones

Siempre separar cada selector en una línea distinta de otro selector. Además separara con un salto de línea cada regla.

/* No recomendado */
a:focus, a:active {
  position: relative; top: 1px;
}
/* Sí recomendado */
h1,
h2,
h3 {
  font-weight: normal;
  line-height: 1.2;
}
html {
  background: #fff;
}

body {
  margin: auto;
  width: 50%;
}

Comillas

A diferencia del HTML, en los CSS es mejor evitar las comillas, y en caso necesario (como en los nombres de tipos de letra) usar la comilla simple .

/* No recomendado */
@import url("//www.example.com/css/estilo.css");

html {
  font-family: "open sans", arial, sans-serif;
}
/* Sí recomendado */
@import url(//www.example.com/css/estilo.css);

html {
  font-family: 'open sans', arial, sans-serif;
}

En fin, son simples sugerencias de reglas, unas más aceptables que otras… pero las que Google utiliza internamente cuando tiene que liberar código al mundo mundial. Así que, si quieres ser un buen googler ya sabes lo que te toca hacer.

NoIndex del robots.txt

¿Te has preguntado si tu fichero robots.txt aparece en Google? La respuesta es que, en principio, sí, puede aparecer. Puedes hacer una prueba con una consulta similar a esta [inurl:”robots.txt”].

Es curioso que un fichero que en principio sólo deberían leer los propios rastreadores aparezca en los resultados de búsqueda y que, por norma general nadie se preocupe de evitar que se indexe… pero ¿es posible no indexar este fichero? La respuesta es simple: sí.

Para eliminar de los resultados de búsqueda este fichero robots.txttenemos dos opciones:

  • Eliminarlo desde el propio robots.txt, es decir, añadir una línea Disallow: /robots.txt.
  • Eliminarlo desde una cabecera HTTP, como X-Robots-Tag: noindex.

Personalmente recomiendo el uso de la segunda opción, ya que el hecho de aplicar un “noindex” implica que sí pueda ser leído pero no mostrado, y la primera, en algún otro buscador, podría ser que no se permitiera su lectura en una siguiente actualización.

Buscadores y países

Hoy estaba repasando algunos datos de StatCounter para repasar el estado del “control absoluto” de Google por el mundo, también conocido como “en qué país Google no manda”. Y la verdade s que me ha sorprendido, porque aquellos pocos países que quedaban con más de la mitad de tráfico de buscadores fuera de las manos del grande de Mountain View se han reducido a 1: China.

Esto me ha hecho analizar un poco más los datos y hacerme la pregunta recursiva que me hago cada vez que tengo que lanzar un proyecto internacional: ¿he de apostar por otro buscador que no sea Google? La respuesta, por supuesto, siempre es sí, aunque Google se quedase con el 100% del tráfico 😉

Aunque pueda parecer que esto es así, y ciertamente Google dispone de una cuota de mercado superior al 90% en casi todo el mundo, siempre quedan algunos países en los que, aunque Google tiene la mayoría hay que observar otros motores que por un tema histórico aún siguen siendo importantes. Como detalle cuando hable de Bing hablaré de Bing+Yahoo! a menos que lo especifique.

  • Estados Unidos: sí, vale, el 80% de la gente usa Google, pero casi un 20% usa el Bing, lo que es bastante interesante teniendo en cuenta que esta cifra va subiendo poco a poco. Bing tiene muy buenos resultados en US debido a los acuerdos y demás información que, todavía, no ofrece en otros países.
  • China: Baidu se lleva un 70% del tráfico y el resto se lo reparten un 15% Google y un 10% Qihoo.
  • Taiwan: Aunque Google gana terreno con un 55%, sin duda Yahoo! aún tiene mucho que decir, ya que tiene una versión especial para este país.
  • Rusia: Google ha ido ganando terreno poco a poco, hasta quedarse con casi un 60% del tráfico, pero el otro 40% sin duda lo tiene Yandex, del que mucha gente usa sus servicios. Además, Yandex está optimizado para el texto cirílico lo que le da mucha ventaja sobre el resto.
  • Hong Kong: Sin duda, también ha ido ganando terreno Google, con un 65% del tráfico pero Yahoo! que también tiene una edición especial, con un 35%, sigue apostando duro.
  • Japón: cada vez Yahoo!, con sólo un 25% de la cuota, va perdiendo camino, y Google lo va ganando con un 70%.
  • Bielorusia, Kazajistán, Ucrania, Uzbekistan, Tajikistan (y otros): estos países que tocan Rusia o que fueron parte de la URSS también siguen teniendo una afinidad entre un 20% y un 10% con Yandex, lo que los sigue haciendo importantes.
  • Korea del Sur: históricamente Naver (9%) y Daum (8%) se han llevado el tráfico, pero Google les ha arrancado la mayoría superando ya el 75%.
  • República Checa: Una vez más, Google se lleva un 75% de las búsquedas, pero el otro 25% se las lleva el buscador local Seznam con un 25%.
  • Eslovenia: residual con un 3% queda Nadji y el resto se lo lleva Google.

Es curioso como antiguas tecnologías de búsqueda y sobretodo diferentes elementos culturales influyen tanto en el uso de los buscadores. Lo de los rusos es básicamente por la codificación del texto, al igual que ocurre con los chinos; los países de más al este es básicamente por un tema cultural… aunque parezca mentira, Google no les gusta porque es “demasiado blanco”, o sea, ellos lo que quieren son páginas “sobre cargadas” de contenido, algo que, como bien sabemos, Google no es precisamente su estilo.

Vale, Google, tiene de media mundial un 90% de cuota, Bing un 7% y el resto casi se lo reparten Yandex y Baidu… Ahora ¿qué vas a hacer con tu SEO?

HTML5 download

En estas dos últimas semanas llevo revisando y revisando elementos del HTML5 que, como ya dije, me apasionan, porque básicamente han hecho mejoras muy impresionantes. Y por eso hoy os voy a hablar de una que me ha gustado muchísimo: el html5 download.

Voy a hacerlo sencillo… imaginad que tengo un fichero que se llama ejemplo123454321.txt. Si pulsáis veréis que es un texto normal y corriente que se abre (en principio) dentro del propio navegador al tratarse de un fichero de texto plano. El código fuente es sencillo:

<a href="ejemplo123454321.txt">ejemplo123454321.txt</a>

ejemplo123454321.txt

Pero, ¿por qué no forzar la descarga y además aprovechar el camino en cambiarle el nombre del fichero? Para ello ha aparecido un atributo en HTML5 que es el downloadque permite esto mismo… sin necesidad de cambiar nada en el servidor… El código sería algo tal que así:

<a href="ejemplo123454322.txt" download="cambiodenombre">ejemplo123454322</a>
(descárgalo como cambiodenombre.txt)

ejemplo123454322.txt (descárgalo como cambiodenombre.txt)

Un detalle importante es que este sistema únicamente funciona si el fichero está en el mismo hostnamedesde donde se hace la petición.

¿Cómo se te queda el cuerpo?

Rel-Canonical, duplicados y versiones móviles

Desde que apareció en escena el rel-canonical me he encontrado en una decena de situaciones distintas de las que, a base de palos, he ido aprendiendo. Hoy me gustaría compair algunas de estas casuísticas en las que me he visto.

Por norma general

Lo ideal del rel-canonical es ponerlo en todas las páginas de un sitio web. Al menos en las páginas públicas (las que los robot son capaces de encontrar). Si tu robots.txt tiene un Disallow de alguna sección, no está de más que estas páginas también lo incluyan. Repito, en general, siempre utilizar el rel-canonical.

El rel-canonical se puede usar de dos formas: vía HTML o vía Header. En el caso del HTML simplemente hemos de colocar la meta-etiqueta en la cabecera de la página:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Javier Casares</title>
  <link rel="canonical" href="http://example.com/">
</head>

La otra posibilidad es la de la cabecera, en cuyo caso hemos de indicar algo tal que así (por ejemplo en PHP):

header("Link: <http://example.com/> rel="canonical"");

Páginas noindex-ables

Cuando tenemos un meta-noindex y un rel-canonical comienzan algunos problemas. Las opciones son dos posibles; la primera de ellas es simplemente indicar el meta-noindex y no indicar el rel-canonical.

URL actual: http://example.com/?prueba=si

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Javier Casares</title>
  <meta name="robots" value="noindex">
</head>

Con esto simplemente esa dirección no se indexaría… porque aunque existe no queremos que se muestre… el problema de esto es que, aunque la dirección exista y no queremos que se indexe porque es exactamente igual que la página principal, se puede generar un ataque. Bing y Google aunque se les indica el “noindex” rastrean y almacenan la página, aunque no la muestran en los resultados de búsqueda, pero se tiene en cuenta, y si es mala, no mola nada.

La otra solución es la de simplemente indicar el rel-canonical…

URL actual: http://example.com/?prueba=si

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Javier Casares</title>
  <link rel="canonical" href="http://example.com/">
</head>

En este caso, esta página también se indexa pero cualquier enlace, fuerza o como se le quiera llamar pasa automáticamente a integrarse con la página principal. En principio la URL “maligna” no debería aparecer en los resultados de búsqueda.

Y os podéis preguntar: Javi, ¿y no sería mejor poner las dos cosas? ¡Miiic!, ¡error!. Si hacemos esto se produce un agujero negro en el espacio infinito que desindexa muchas cosas. Vosotros pensáis en algo tal que así:

URL actual: http://example.com/?prueba=si

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Javier Casares</title>
  <link rel="canonical" href="http://example.com/">
  <meta name="robots" value="noindex">
</head>

Si hacemos esto, se produce una paradoja extraña. Lo que ocurre es que el rel-canonical se prioriza sobre el meta-noindex. Esto significa que:

  1. El buscador toma la URL http://example.com/?prueba=si y la almacena como http://example.com/
  2. El buscador toma la URL http://example.com/ y le aplica el noindex.

¡Bien! Acabamos de desindexar de Google y Bing nuestra página principal. Sí, esto pasa… así que, niños, no pongáis nunca un rel-canonical con un meta-noindex… pero… ¿qué corre si el rel-canonical apunta a la URL correcta que ya tenía un meta-noindex anteriormente? Os explico la situación.

Imaginad que tenéis una página que, antes de pensar en ponerles el rel-canonical ya tenía puesto el meta-noindex. Es una URL correcta (o sea, la URL del navegador y la del rel-canonical coinciden) por lo que… ¿por qué no podemos aplicar el rel-canonical si Javi ha dicho al principio que recomienda ponerlo siempre? Pues, en este caso sí que tendría sentido ponerse.

URL actual: http://example.com/?pagina=5

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Javier Casares</title>
  <meta name="robots" value="noindex">
</head>

Imaginemos que la paginación de mi sitio funciona por parámetros, y que yo ya tenía el código anterior… esta página, tal y como está no se indexa, lo que es correcto porque yo lo he decidido así… ¿por qué no poner algo como esto?

URL actual: http://example.com/?pagina=5

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Javier Casares</title>
  <link rel="canonical" href="http://example.com/?pagina=5">
  <meta name="robots" value="noindex">
</head>

Pues, en este caso en principio el código sí que sería correcto.

Versiones móviles

Versiones, hoy en día, para dispositivos hay 3: escritorio (versión normal), móviles (los zapatófonos) y smartphones (los que soportan HTML5). También hay varias formas de afrontar este tipo de páginas… lo que se recomienda (aunque a mi hay detalles que no me convencen, aunque se pueden llegar a corregir con un poco de ingeniería) es que se utilice responsive web design. Esto significa que dependiendo de ciertas especificaciones se carga un CSS u otro. Pero hay otras opciones como que se carguen CSS distintos según el tipo de “navegador” o directamente que haya URLs separadas según el tipo de web.

El caso que voy a tratar es concretamente el tercero, o sea, el caso en el que las versiones de los distintos dispositivos tienen URL distintas. Por ejemplo, podemos tener estas 3 versiones:

URL versión escritorio: http://www.example.com/page-one/

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Example</title>
  <link rel="alternate" media="only screen and (max-width: 640px)" href="http://m.example.com/page-one/">
  <link rel="alternate" media="handheld" href="http://phone.example.com/page-one/">
  <link rel="canonical" href="http://www.example.com/page-one/">
</head>

En este caso indicamos una URL alternativa para dispositivos móviles http://m.example.com/page-one/ y otra URL para dispositivos inteligentes http://phone.example.com/page-one/. ¿Qué habría que indicar en cada una de estas versiones?

URL versión móvil: http://m.example.com/page-one/

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Example</title>
  <link rel="canonical" href="http://www.example.com/page-one/">
</head>
URL versión smartphone: http://phone.example.com/page-one/

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Example</title>
  <link rel="canonical" href="http://www.example.com/page-one/">
</head>

Y en principio hasta aquí todo lo que hay que saber sobre los rel-canonical… pero antes de acabar, un detalle sobre esto último que tiene que ver con los Sitemaps… y es que en los Sitemaps XML también se le puede indicar las direcciones URL alternativas para las versiones móviles…

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml">
  <url>
    <loc>http://www.example.com/page-one/</loc>
    <xhtml:link rel="alternate" media="only screen and (max-width: 640px)" href="http://m.example.com/page-one/" />
    <xhtml:link rel="alternate" media="handheld" href="http://phone.example.com/page-one/" />
  </url>
</urlset>

¡Ala, ahí queda eso!

URL y las letras raras

Una de las preguntas recursivas en SEO, y sobre todo cuando se plantea un proyecto muy internacional es el de qué tipo de caracteres en las URL hay que usar en un sitio web que no es “occidental”. Supongo que cuando se hace uso del concepto “occidental” se hace referencia al sistema de caracteres ASCII.

La respuesta a este tipo de preguntas es un poco complejo. Si bien está permitido y es posible codificar las URL, la recomendación (de principios de Internet) es que no se haga uso de otros caracteres que no sean parte de un rango concreto del ASCII.

Para explicarlo todo mejor me voy a basar en la documentación oficial, es decir, los RFC, en este caso los siguientes:

  • RFC 1630: Universal Resource Identifiers in WWW
  • RFC 1736: Functional Recommendations for Internet Resource Locators
  • RFC 1737: Functional Requirements for Uniform Resource Names
  • RFC 1738: Uniform Resource Locators (URL)
  • RFC 1808: Relative Uniform Resource Locators
  • RFC 2368: The mailto URL scheme
  • RFC 2396: Uniform Resource Identifiers (URI): Generic Syntax
  • RFC 2732: Format for Literal IPv6 Addresses in URL’s
  • RFC 3491: Punycode: A Bootstring encoding of Unicode for Internationalized Domain Names in Applications (IDNA)
  • RFC 3986: Uniform Resource Identifier (URI): Generic Syntax
  • RFC 3987: Internationalized Resource Identifiers (IRIs)
  • RFC 4248: The telnet URI Scheme
  • RFC 4266: The gopher URI Scheme
  • RFC 5987: Character Set and Language Encoding for Hypertext Transfer Protocol (HTTP) Header Field Parameters
  • RFC 6196: Moving mailserver: URI Scheme to Historic
  • RFC 6270: The ‘tn3270’ URI Scheme

Principalmente los RFC que hablan o que dejan de forma definitiva cómo ha de ser la estructura y qué y cómo funciona son el 1630 (documento de Tim Berners-Lee de Junio de 1994), 3986 y el 3987, con el añadido del 5987. ¿Y qué dicen estos estándar?

En el primer documento se habla de las diferencias entre URI, URL y URN, de la necesidad de establecer un sistema universal. El objetivo final tenía 3 propósitos: que fuera extensible para que se pudieran añadir nuevos formatos y estructuras en el futuro, completo de forma que se pudiera codificar cualquier sistema e “imprimible” por lo que se sugería el uso del ASCII 7-bits para que se pudiera escribir cualquier dirección “a mano” (vamos, en un papel, de forma sencilla).

NOTA sobre los recursos: Una URI es lo que conocemos como la dirección completa que aparece en el navegador, lo que incluye el “protocolo” o “schema”. Ejemplo: http://example.com/example.html?test=1#seccion Una URL es la dirección sin necesidad de incorporar el protocolo… Ejemplo: //example.com/example.html?test=1#seccion Un URN es simplemente el nombre de un recurso… Ejemplo: urn:isbn:9788441527829 Por eso, cuando hablemos de SEO propiamente dicho, habría que hablar de las URL ya que -en principio- no hay que tener en cuenta el protocolo (seguro o no) del HTTP.

Como detalles curiosos, se prefirió elegir la escritura de izquierda a derecha que la de derecha a izquierda por se la más común, y el hecho de haber elegido los “dos puntos” como separador (en los protocolos) fue algo de forma “arbitraria”.

Se definió el uso de los llamados caracteres “seguros” y “no-seguros”. Es por esto que quedaron algunos caracteres con funciones especiales:

  • ”%” (ASCII 25 hex): Se usa para la codificación de caracteres “extraños”.
  • ”/” (ASCII 2F hex): Se usa para delimitar subfragmentos de texto que dependen por herencia (vamos, lo que conocemos como “carpetas” o “niveles”). También se definía lo mismo con un punto (.) o dos puntos (..).
  • ”#” (ASCII 23 hex): Se usa como delimitador para separar la URL de un objeto de un identificador.
  • ”?” (ASCII 3F hex): Se usa como delimitador de la URI de un objeto “consultable” (vamos, un parámetro). En estos parámetros el símbolo “+” se usaría como “unión”. En el caso de tener que poner un símbolo “+” habría que codificarlo.
  • ”*” (ASCII 2A hex) y “!” (ASCII 21 hex) se reservan para significados distintos según el schema pertinente (es decir, según el protocolo que se use: HTTP, Telnet, Mail, Gopher…).

Un detalle curioso es que, si os fijáis, hoy en día usamos otra serie de caracteres como habituales que en su momento no pasaron este corte. El caso más claro era el del “guión”. En aquel momento se planteaba que el guión no era un carácter especial.

Y tras esta base llegan un montón de RFC que, hoy en día, acaban siendo actualizados por el 3986. Este es el documento que hoy en día indica cómo han de ser las URI, en una sintaxis genérica. Es curioso que este documento es de 11 años después del primero, o sea, de enero de 2005, lo que significa que se podría plantear como una versión 2 muy importante y que deja claro cómo ha de ser el futuro de Internet.

Cuando hablamos de cómo ha de ser una URI (siguiendo lo que comentaba de los 3 grandes puntos al principio) tenemos que:

  • Una URI es una secuencia de caracteres que no siempre representa una secuencia de “octetos”.
  • Una URI debe poder ser transcrita desde una “no-red” (un papel, vamos) y debería constar de una serie de caracteres que pueden ser introducidos a un ordenador a través de un teclado, independientemente del idioma.
  • Una URI debería ser fácilmente recordable por las personas, y para ello debe estar formada por subpartes fácilmente familiares y significantes.

¿Qué caracteres deberíamos usar? Básicamente todo se basa en el US-ASCII. El símbolo %quedará como sistema de codificación. Esto implica que los caracteres no-seguros se pintarán como % seguido de 2 números. Estos números harán referencia al hexadecimal. Por ejemplo, el %20 hace referencia al caracter 20 del ASCII, que es el “espacio”. El resto de caracteres especiales queda definido en la lista: “!”, “$”, “&”, “’”, “(“, “)”, “*”, “+”, “,”, “;” y “=”. Los caracteres no reservados son: “letras”, “números”, “-“, “.”, “_” y “~”. En estos últimos casos, cuando uno de ellos se encuentre codificado en la URL, se debe convertir a su valor original. Esto significa que si nos encontramos con una dirección así:

//example.com/ejemplo%2Dde%2Durl%2Ehtml

el navegador (o cualquier sistema) debe dejarlo estandarizado en:

//example.com/ejemplo-de-url.html

De esta forma, estos son caracteres semi-reservados ya que tienen un trato especial.

Las direcciones URI estarán formadas por los siguientes componentes:

  foo://example.com:8042/over/there?name=ferret#nose
  _/   ______________/_________/ _________/ __/
   |           |            |            |        |
scheme     authority       path        query   fragment
   |   _____________________|__
  /  /                        
  urn:example:animal:ferret:nose

No voy a entrar en qué ha de tener el “schema” o el “authority”, porque eso está muy limitado. De cara al SEO y a la Arquitectura de la Información, lo importante es el “path”, el “query” y el “fragment”.

¿Qué elementos son destacables en el “path”? Pues para empezar el uso de “.” o de “..”. Esto indica un nivel actual o un nivel “anterior”. Otros elementos serían el punto y coma “;” y el igual “=” que se reservan frecuentemente para delimitar parámetros y valores. La coma “,” también se reserva para un uso similar al anterior.

¿Qué elementos son destacables en el “query”? Pues principalmente el signo de interrogación “?” que indica el comienzo.

¿Qué elementos son destacables en el “fragment”? Pues principalmente el signo almohadilla “#” que indica el comienzo.

A lo largo de lo que llevo comentado he hablado de los dos puntos “..”. Este caso es muy concreto porque, al igual que los caracteres normales se han de recodificar, las direcciones URL que incluyan este caso también deberían codificarse. Esto es como ejemplo, lo siguiente:

//example.com/ejemplo-1/../ejemplo-2/

En realidad quedaría como:

//example.com/ejemplo-2/

Con respecto a la normalización del “schema” hay que tener presente que estas 4 direcciones son iguales:

http://example.com
http://example.com/
http://example.com:/
http://example.com:80/
HTTP://EXAMPLE.COM/

Pero de entre estas 4 direcciones hay que plantearse que una es la óptima. Esto significa que hay que aplicar algunas reglas. Para comenzar lo ideal es que acabe en “barra”, y que si el puerto es el de por defecto no se incluya. Además, esta primera parte debe estar en minúsculas. Esto significa que la dirección URI óptima sería la siguiente:

http://example.com/

Con respecto a otros componentes, y que hacen referencia a la “barra final”, tenemos por ejemplo estas dos direcciones:

http://example.com/data
http://example.com/data/

Aquí hay un detalle. Si estas dos direcciones acaban mostrando el mismo contenido (que es lo habitual), es más que recomendable que se utilice la de la barra final como principal.

http://example.com/data/

Cambiando al RFC 3987 tenemos un nuevo concepto delante: Internationalized Resource Identifier (IRI). Esto es un complemento de las URI, que es una secuencia de caracteres del Unicode / ISO 10646, formado por cerca de cien mil caracteres abstractos. Al final, como resumen, podemos decir que es el formato conocido como UTF-16.

¿Por qué hacer aparecer el IRI? Básicamente porque aunque se recomienda convertir caracteres no-ASCII a ASCII, hay veces que es conversión implica que algunas palabras no acaben de ser completamente razonables, o pueden implicar ambigüedad.

¿Cuándo se debe usar un IRI sobre un URI? Los protocolos deben estar designados para los IRI, algo que a priori no nos debería importar mucho para SEO y para nuestro trabajo habitual, pero, sí que hay otro punto y es el de usar IRI cuando la URI está codificada en UTF-8. El objetivo es cambiar las IRI a la codificación estándar de URI.

Personalmente las direcciones tales como:

http://example.com/

Sitios web más accesibles

He decidido darle un repaso a todo lo que ARIA implica en el desarrollo de un sitio web. WAI-ARIA (Web Accessibility Initiative – Accessible Rich Internet Applications) son unas mejoras del HTML para mejorar la accesibilidad de los sitios web. Como ya dije en su momento, básicamente le da algo más de inteligencia semántica a los sitios.

Pero no hemos de olvidar que el propio HTML5 a diferencia de sus versiones anteriores ha incorporado que prácticamente todas sus etiquetas ya llevan incorporados ciertos elementos semánticos. Por poner un ejemplo, la etiqueta H1 ya implica un header. La cuestión es… ¿cuándo y cómo hay que usar ARIA en HTML?

La primera de las normas es bastante sencilla. Si un elemento HTML ya incluye semántica ARIA integrada, no hace falta indicarla, a menos que la queramos cambiar.

La segunda de las normas también es sencilla, aunque a mi personalmente no me gusta mucho. Es recomendable no sobre escribir las reglas ARIA de los elementos. Por poner un ejemplo:

No se debe hacer así:

<h1 role="button">botón en la cabecera</h1>

Sería mejor hacerlo así:

<h1><span role="button">botón en la cabecera</span></h1>

Aunque si lo queremos hacer óptimo, podemos usar:

<h1><button>botón en la cabecera</button></h1>

¿Qué significa esto? Pues que si por ejemplo hacemos algo de este estilo:

<h1 role=button>texto</h1>

Realmente lo que tendríamos a nivel significado es esto:

<button>texto</button>

Otro ejemplo sería el siguiente:

<button role="heading" aria-level="1">texto</button>

Que nos dejaría con algo tan simple como esto:

<h1>texto</h1>

Vale, hasta aquí nos queda claro que es importante usar el significado que viene por defecto en los diferentes elementos o la oportunidad de sobre escribir el significado de los mismos, pero… ¿qué ocurre con todo ese código “de mierda” que metemos en las páginas que en principio llevan significado de por sí, pero que realmente sólo usamos para “dar formato” a lo que queremos? Pues para este tipo de código podemos utilizar un sistema que elimina cualquier significado: el role="presentation".

Un detalle de este parámetro es que se come el significado también de cualquier etiqueta hija que incluya. Para poner un ejemplo algo “complejo” os dejo este:

<table role="presentation">
  <tr>
    <td>
      <table>
        <tr>
          <td><abbr title="Application Programming Interface">API</abbr></td>
        <tr>
      </table>
    </td>
  </tr>
</table>

Realmente, su significado “real” quedaría mucho más reducido, a esto:

<>
  <>
    <>
      <table>
        <tr>
          <td><abbr title="Application Programming Interface">API</abbr></td>
        <tr>
      </table>
    </>
  </>
</>

Personalmente, desde el punto de vista SEO este último elemento debería tener todo el sentido del mundo ya que implicaría quitarle significado a toda la basura de código que muchas veces se genera en determinados sitios web. Aún así, Bing y Google tratan ARIA de formas muy distintas y dispersas y no queda claro su funcionamiento. Después de esto, mi pensamiento es que si se hace bien y se pone el código como se debe, mal no debe hacer.

¿Cómo se oculta información? Habitualmente usamos a través de CSS el display:none o el visibility:hidden, pero esto simplemente lo que hace es no mostrarlo, pero sigue siendo “visible” desde el punto de vista de la accesibilidad. ¿Cómo eliminarlo? Pues añadiendo el aria-hidden. Hay que tener tener en cuenta que una de las novedades en HTML5 es que todos los elementos del DOM incluyen el nuevo atributo hidden, lo que significa que otra forma de ocultar contenidos se puede aplicar con un pequeño JavaScript tal que así:

<script>
  function ocultar() {
    document.getElementById('prueba').hidden = true;
  }
</script>

Existen muchos roles en el sistema, y como ya he comentado al principio la mayoría de etiquetas del HTML ya incluyen su significado semántico… pero no todos los elementos disponen de sus propios roles.

  • Cualquier elemento: como ya he comentado antes, cualquier elemento podría usar el role="presentation".
  • address: podría incorporar en caso necesario el role="contentinfo" que amplia la información del documento actual.
  • article: los navegadores aún no indican su rol por defecto, así que habría que indicarlo expresamente con role="article".
  • details: como el anterior, aún no va de serie, así que hay que indicarle el role="group".
  • dialog: otro que debería y no lo lleva de serie, con el role="dialog".
  • div, p, pre y blockquote: no tienen un rol definido por defecto, así que les podemos asignar el que nos venga en gana según necesitemos.
  • footer: es curioso que este elemento no lleve un significado implícito, por lo que si en la página hay un pie “general”, a ese en concreto se le puede asignar el role="contentinfo".
  • header: al igual que el pie, este tampoco lleva implícito nada, por lo que podríamos utilizar por ejemplo el role="banner" si es la cabecera principal.
  • main: este elemento que se está planteando par el HTML5.1 debería ir acompañado siempre del role="main".
  • nav: indica una navegación por lo que debería ir acompañado del role="navigation".
  • span: el “tag inútil” tiene una gran ventaja… al igual que el div se le puede incorporar cualquier rol.
  • table: aunque no incopora ningún significado por defecto hay dos opciones que sí que se podrían utilizar; la primera es cuando se le da uso de “diseño”, por lo que es inútil y se debería eliminar cualquier significado con el role="presentation"; en el caso de que se le de un uso de tabla pura, se le podría dar el role="grid".

A parte de estos elementos que son principalmente contenedores tenemos otros como em, strong, small, s, cite, q, dfn, abbr, time, code, var, samp, kbd, sub, sup, i, b, u, mark, ruby, rt, rp, bdi, bdo, br, wbr… que como son utilizables para dar formato no incorporan ningún tipo de significado semántico. Se les puede dar el rol que se quiera, pero personalmente no creo que sea recomendable.

Hasta ahora he comentado varios de los posibles roles que se pueden utilizar, pero la lista de roles es bastante grande…

  • alert: Un mensaje importante y con una duración en el tiempo limitada.
  • alertdialog: Un bloque que incluye un mensaje de alerta.
  • application: Todo lo contrario a un “documento”. O sea, que no es una web.
  • article: Parte de un documento que se puede tratar como un elemento independiente.
  • banner: Bloque que suele contener contenido para todo el sitio.
  • button: Sistema que reacciona tras un clic o presión.
  • checkbox: Entrada que tiene 3 posibles estados: verdadero, falso o mixto.
  • columnheader: Celda que contiene la información de una columna.
  • combobox: Un listado en el que además se pueden añadir opciones.
  • complementary: Contenido complementario al contenido principal pero que a su vez tiene significado propio.
  • contentinfo: Información relacionada al contenido principal.
  • definition: Definición de un concepto.
  • dialog: Ventana que detiene el proceso actual a la espera de que el usuario introduzca información para continuar.
  • directory: Referencia a un grupo de elementos (como si fuera un índice).
  • document: Todo el contenido de una página web.
  • form: Un formulario (y todo lo que lo acompaña).
  • grid: Como una tabla, tiene filas y columnas con celdas.
  • gridcell: Una celda.
  • group: Una lista de objetos pero que no es un directorio.
  • heading: La cabecera del contenido de una página.
  • img: Colección de elementos que forma una imagen.
  • link: Referencia que, cuando se pulsa, hace que el navegador vaya a ese recurso.
  • list: Lista de elementos no interactivos.
  • listbox: Lista de elementos interactivos con el usuario.
  • listitem: Elemento de una lista o directorio.
  • log: Zona en la que se va añadiendo información nueva dejando paso de la anterior.
  • main: Contenido principal del documento.
  • marquee: Zona en la que la información (no esencial) va cambiando.
  • math: Expresión matemática.
  • menu: Lista de opciones para un usuario.
  • menubar: Menú habitualmente siempre visible y en horizontal.
  • menuitem: Opción dentro de un menú.
  • menuitemcheckbox: Opción de un menú que tiene 3 posibles estados: verdadero, falso o mixto.
  • menuitemradio: Opción de menú que sólo permite una posibilidad a la vez.
  • navigation: Elementos que permiten la navegación por páginas externas o internas.
  • note: Bloque que añade información puntual al documento principal.
  • option: Elemento seleccionable de una lista.
  • presentation: Elemento que no debe ser accesible.
  • progressbar: Barra de progreso.
  • radio: Elementos que sólo pueden ser seleccionables una vez.
  • radiogroup: Grupo de elementos que sólo pueden ser seleccionables una vez.
  • region: Agrupación de contenidos que podrían estar en un directorio.
  • row: Fila de celdas.
  • rowgroup: Grupo de filas de celdas.
  • rowheader: Celda que contiene la información de una fila de celdas.
  • scrollbar: Barra de navegación que controla el scroll de una zona.
  • search: Bloque que agrupa elementos que permiten realizar búsquedas.
  • separator: Separador de secciones en un contenido o grupos de menús.
  • slider: Lugar de selección entre valores de un determinado rango.
  • spinbutton: Rango de opciones en los que el usuario ha de elegir.
  • status: Bloque de información para el usuario no tan importante como una alerta.
  • tab: Etiquetas que permiten al usuario una ayuda sobre el contenido.
  • tablist: Lista de “tabs”.
  • tabpanel: Contenedor de “tablist”.
  • textbox: Texto libre.
  • timer: Contador de tiempo.
  • toolbar: Colección de botones.
  • tooltip: Contenido contextual de información de un elemento.
  • tree: Lista que permite extender o contraer sus elementos.
  • treegrid: Listas por filas que permiten expandir o contraer sus elementos.
  • treeitem: Elemento de un árbol.

Ahora que tenemos todo esto sobre la mesa… Cuando hablan de la Web 3.0 ¿se refieren a esto?

HTML5 Server-Sent Events

Por si no lo sabíais el HTML5 me apasiona, principalmente no por el HTML en sí sino por todo lo que lleva a su alrededor. Y hoy toca hablar de los eventos Server-Sent. Básicamente este sistema lo que permite es que el navegador reciba información de forma automática de una fuente de datos sin necesidad de recargar la página.

El funcionamiento es tan sencillo como indicar la URL desde la que se cargarán los datos y esperar a que los datos vayan apareciendo por pantalla. Como datos a tener en cuenta es que esto no funciona en Internet Explorer (ni en la versión 10) aunque sí que lo hace en Firefox 6 y Chrome. Personalmente a mi en Chrome no em acaba de funcionar, intuyo, por un problema con saltos de línea y similares.

Y es que la fuente de datos ha de enviar los textos comenzando por data: y finalizando por un salto de línea o End Of Line, algo que parece que no acaba de dar el peso en todos sitios.

El ejemplo que he preparado (descargar) básicamente muestra por pantalla números aleatorios… aunque se puede cargar prácticamente cualquier cosa.

El único inconveniente es que no he visto en la documentación la forma de cambiar la frecuencia con la que el navegador llama para la carga de los datos. Aún así, gracias a esto nos evitaremos el uso de iframes o de peticiones AJAX.

Piensa en asíncrono

Sin duda una de las mejoras del HTML5 es la posibilidad de cargar determinados elementos de forma asíncrona en la página. Y es que si tus usuarios utilizan navegadores de versiones superiores a Firefox 3.6, IE 10, Chrome 2, Safari 5, iOS 5 o Android 3 dispones de la posibilidad de hacerlo fácil:

<script async src="http://example.com/javascript.js"></script>

La carga de los scripts se puede hacer de muchas formas… la más sencilla, por ejemplo si es de un recurso propio, se puede hacer de esta forma:

<script>
  var resource = document.createElement('script');
  resource.src = "http://example.com/javascript.js";
  var script = document.getElementsByTagName('script')[0];
  script.parentNode.insertBefore(resource, script);
</script>

O también de esta forma… ambas son similares:

<script>
  (function(d, t) {
    var g = d.createElement(t),
    s = d.getElementsByTagName(t)[0];
    g.src = 'http://example.com/javascript.js';
    s.parentNode.insertBefore(g, s);
  }(document, 'script'));
</script>

Esta es una forma que permite la carga aunque no es del todo efectiva ya que no siempre se carga asíncronamente. Para ello, sobretodo si es de scripts externos se puede usar algo más así:

<script>
  (function(){
    var a = document.createElement('script');
    a.type = 'text/javascript';
    a.async = true;
    a.src = 'http://example.com/javascript.js';
    (document.getElementsByTagName('head')[0]||document.getElementsByTagName('body')[0]).appendChild(a);
  })();
</script>

Ahora que ya sabemos cargar los scripts de forma sencilla y asíncrona… ¿por qué no cargar algunos scripts “famosos” de forma sencilla y sin que afecte negativamente a tu sitio web?

El código de Facebook:

<div id="fb-root"></div>
<script>
  (function(d, s, id) {
    var js, fjs = d.getElementsByTagName(s)[0];
    if (d.getElementById(id)) return;
    js = d.createElement(s);
    js.id = id;
    js.src = "http://connect.facebook.net/es_ES/all.js#xfbml=1";
    fjs.parentNode.insertBefore(js, fjs);
  }(document, 'script', 'facebook-jssdk'));
</script>

El código de Twitter:

<a href="https://twitter.com/share" class="twitter-share-button">Twitear</a>
<script>
  !function(d,s,id) { 
    var js,fjs = d.getElementsByTagName(s)[0];
    if(!d.getElementById(id)) { 
      js = d.createElement(s);
      js.id = id;
      js.src = "http://platform.twitter.com/widgets.js";
      fjs.parentNode.insertBefore(js,fjs);
    }
  } (document,"script","twitter-wjs");
</script>

El código de Google+:

<g:plusone annotation="inline"></g:plusone>
<script type="text/javascript">
  (function() {
    var po = document.createElement('script');
    po.type = 'text/javascript';
    po.async = true;
    po.src = 'http://apis.google.com/js/plusone.js';
    var s = document.getElementsByTagName('script')[0];
    s.parentNode.insertBefore(po, s);
  })();
</script>

Pero… ¿no sería más sencillo mantener un único código para todo? La solución es bastante sencilla, ya que al fin y al cabo en todos los casos se carga de la misma forma…

<script>
  (function(doc, script) {
    var js, fjs = doc.getElementsByTagName(script)[0], add = function(url, id) {
      if (doc.getElementById(id)) {
        return;
      }
      js = doc.createElement(script);
      js.src = url;
      id && (js.id = id);
      fjs.parentNode.insertBefore(js, fjs);
    };
    add('http://www.google-analytics.com/ga.js', 'ga');
    add('http://apis.google.com/js/plusone.js');
    add('http://connect.facebook.net/es_ES/all.js', 'facebook-jssdk');
    add('http://platform.twitter.com/widgets.js', 'twitter-wjs');
  } (document, 'script'));
</script>

¡Ahora a reprogramar!

WordPress y algunos problemas de phishing / spam

Desde hace unos pocos meses cada vez más veo hackeosen los WordPress. No tengo muy claro si es un problema interno del propio WordPress o si es de algún plugin (sí que me he encontrado en algún caso problemas con algunas plantillas que no estaban actualizadas y que usaban software externo para subir ficheros).

La cuestión es que como a veces e difícil darse cuenta de si te han colado algún bicho, me propuse hace un par de días a hacer una pequeña y simple mejora que, en general, debe de funcionar. La idea es sencilla: no dejar funcionar el PHP en las carpetas de subida de ficheros.

En general los usuarios tienen configurada la carpeta /wp-content/uploads/ y todo lo que suele haber aquí son imágenes o ficheros binarios, pero nada ejecutable. Si este es el caso, se puede incluir un fichero .htaccessen esta carpeta con el siguiente contenido:

RewriteEngine off
RemoveHandler .php
RemoveType .php
php_flag engine off

Básicamente aquí se consiguen varias cosas: que no funcione el “mod_rewrite”, que PHP no pueda ejecutar los ficheros PHP y, de paso, directamente apagar el PHP en estas carpetas.

Seguramente este fichero se podrá subir en algunas otras carpetas dentro de toda la estructura, aunque mi recomendación es que sólo se aplique a las carpetas a las que el usuario tiene acceso (¡cuidado! que depende de cómo esta configuración se hereda en subcarpetas) y en las carpetas de caché.

Resolución de sub-millisegundos en WPO

Sin duda que el WPO se haya convertido en un estándares un gran paso, pero como ya comenté una vez y no me caso de repetir, el WPO es cómo la Fórmula 1. Y esto tiene un problema con los relojes actuales… y es que el tiempo lo miden en milisegundos.

Esto hace que la información detallada que tenemos es la cifra que ha pasado desde el 1 de enero de 1970 (hora UTC). ¿Qué ocurre con esto? Que si queremos medir, por ejemplo, los “frames por segundo” tenemos información sesgada, ya que no es 100% medible con exactitud.

Ahora se está planteando un estándar para aumentar la resolución en algunos casos (como por ejemplo la API del “performance”) llamada High Resolution Time. Con esto conseguiríamos tener 1.000 veces un milisegundo, que no es poco.

Ahora podemos conseguir los datos (en milisegundos, normales) de la siguiente forma en cada navegador… a ver a partir de qué versión disponemos de estos nuevos datos mucho mayores.

En Firefox (a partir de la versión 7.0):

  • Entrar en una página web
  • Pulsar F12 para abrir las herramientas
  • Pulsar en la pestaña de Consola
  • En la parte final tras las tres »> escribir: performance.timing
  • Pulsar sobre la línea de resultados PerformanceTiming y desplegar los resultados.

En Chrome (a partir de la versión 6.0):

  • Entrar en una página web
  • Pulsar F12 para abrir las herramientas
  • Pulsar en la pestaña de Consola
  • En la parte final tras las tres »> escribir: performance.timing
  • Pulsar sobre la línea de resultados PerformanceTiming y desplegar los resultados.

En Explorer (a partir de la versión 9.0):

  • Entrar en una página web
  • Pulsar F12 para abrir las herramientas
  • Pulsar en la pestaña de Consola
  • En la parte final tras las dos » escribir: performance.timing
  • Tras algunos de los resultados de PerformanceTiming, pulsar en “Agregar para ver”.

Si quieres hacer algunas pruebas con estos datos, puedes usar la herramienta de Análisis de Datos de Performance.Timing.

WordPress Child Themes y WPO

Desde hace unas cuantas versiones de WordPress que está disponible la opción de los Child Themes. Este sistema una de las cosas que pide es que, la creación de este sistema tiene como base hacer un @importdel CSS padre.

En este sentido, aunque los ficheros PHP sobre escriben los otros, por lo que no hay afectación directa sobre el WPO, sí que hay un detalle que no es del todo correcto, y es precisamente ese, el base para crear un hijo, el de hacer ese import.

Y es que los @import son una de las reglas “prohibidas” en cuanto a WPO. Así que… ¿qué solución tenemos para arreglar esto?. La primera de ellas es hacer un copy & pastede todo el contenido del fichero. ¿Problema? Que si hay una actualización de la plantilla padre la información de la plantilla hijo no se actualizará.

La otra opción, que es algo más elaborada, lo que viene a hacer es lo mismo pero de forma automatizada. Para empezar el fichero no será un CSS al uso, sino que será físicamente un fichero PHP. En esa carpeta tendremos que incluir un .htaccess que haga un “rewrite” del .CSS al .PHP. Con esto tenemos solventado que el sistema vea que eso es una hoja de estilos válida. El fichero .htaccessserá algo tal que así:

RewriteEngine On
RewriteRule ^style.css style.php

Ahora lo siguiente es automatizar el fichero .CSS. Para ello debemos hacer un par de temas. Lo primero es pensar que es un fichero programado, de forma que hay que devolver el contenido en el formato correcto. Así, la primera línea del fichero será algo tal que:

header('Content-Type: text/css');

Lo siguiente será incluir el contenido del fichero CSS original. Por ejemplo:

$contenidocss = trim(file_get_contents('../twentyeleven/style.css'));
if($contenidocss) {
  echo $contenidocss;
}

Si lo juntamos todo, nos quedaría algo similar a esto en el fichero style.php:

<?php
header('Content-Type: text/css');
?>
/*
Theme Name:     Twenty Eleven Child
Theme URI:      http://example.com/
Description:    Child theme for the Twenty Eleven theme 
Author:         Your name here
Author URI:     http://example.com/about/
Template:       twentyeleven
Version:        0.1.0
*/
<?php
$contenidocss = trim(file_get_contents('../twentyeleven/style.css'));
if($contenidocss) {
  echo $contenidocss;
}
?>
// a partir de aquí van los cambios y nuestros retoques del CSS
body {
  font-family: Verdana;
}

Con esto conseguiremos que el waterfall del sitio web no se vea bloqueado por culpa de ese @import en el CSS, que además siempre está al principio de las peticiones y no tiene ningún sentido.

SEO negativo

Los que me conocen bien saben que no estoy muy de acuerdo en hacer políticas muy activas de link-building, al menos no hacerlas hasta que no ha pasado una serie de cosas (un montón de acciones SEO pro activas en el sitio).

Pues bien, ahora (y esto lo publico porque ya me ha pasado en dos ocasiones) Google está por la labor de amargarnos un poco el verano con una serie de mensajes en los que se informa sobre “enlaces no naturales”. En concreto el mensaje es el siguiente:

Dear site owner or webmaster of http://example.com/,

We've detected that some of your site's pages may be using techniques that are outside Google's Webmaster Guidelines.

Specifically, look for possibly artificial or unnatural links pointing to your site that could be intended to manipulate PageRank. Examples of unnatural linking could include buying links to pass PageRank or participating in link schemes.

We encourage you to make changes to your site so that it meets our quality guidelines. Once you've made these changes, please submit your site for reconsideration in Google's search results.

If you find unnatural links to your site that you are unable to control or remove, please provide the details in your reconsideration request.

If you have any questions about how to resolve this issue, please see our Webmaster Help Forum for support.

Sincerely,
Google Search Quality Team

Por un lado, lo más divertido de esto es que el sitio en el que ocurrió esto, como digo, no había tenido una campaña de enlaces pro activo, pero sí que días antes estaba comenzando a tener un aumento de enlaces ya que coincidía con un evento que se produjo en esas fechas. Tras haber informado hasta en 3 ocasiones por el formulario de reinclusión que no se había hecho ningún tipo de estrategia de enlaces, y que tampoco teníamos manera de comprobar qué enlaces eran los que supuestamente nos estaban afectando, lo único que queríamos era más información para ver si podíamos realizar alguna acción legal contra los que supuestamente estaban afectándonos negativamente. Al cabo de una semana volvió a aparecer el mismo mensaje de arriba, y de vuelta una respuesta similar en el formulario, y al cabo de una semana lo mismo. Al final, ya no tuve remedio que dejarlo pasar y un par de semanas después la web cayó en una degradación.

Este mensaje ha vuelto a florecer hoy en otro proyecto. La diferencia es que sé que en este proyecto (que no es directamente mío ni lo controlo yo) sí que tengo entendido que se ha hecho una estrategia de enlaces pro activa cuando el proyecto tenía otro tipo de problemas más graves (principalmente contenidos duplicados, en los cuales sí que he estado ayudando para resolver la problemática). A ver ahora cómo sale este asunto y si los responsables de los enlaces son capaces de eliminar los enlaces que se han creado de forma “falsa”, avisando a Google de que se han eliminado.

A raíz de encontrarme esta problemática, he estado rascando un poco en los foros del propio Google y ha aparecido una serie de entradas interesantes llamada Processing Fees for Link Removal Requests en los que hay una acalorada discusión desde hace un par de días en los que. básicamente, se habla de que una persona está solicitando a un sitio web que se elimine un enlace (que él nunca ha solicitado) y le piden hasta 500 dólares por la eliminación de dicho enlace. Entre estos mensajes me gustaría destacar uno que dice tener mucho respeto por Google, pero que viene a decir que se le ha ido la olla al sistema de detección de supuestos enlaces falsos, e incluso comenta que podría haber una oleada de sitios (e incluso como modelo de negocio) que es el de pagar por eliminar enlaces. Incluso, este mismo usuario en otra entrada comenta el nuevo modelo de negocio de crear directorios y penalizarlospara luego pedir dinero por la eliminación de dichos enlaces que se han añadido rastreando otros sitios o simplemente rastreando la web.

Bienvenido al mundo del SEO negativo.