Funciones interesantes para WordPress (1)

Voy a comenzar una serie de entradas que tratan sobre WordPress. Como ya sabréis, WordPress permite tener en la carpeta del “theme” un fichero llamado functions.php en el que se pueden incluir una serie de funciones que se pueden ejecutar en cualquier lugar del diseño, o pueden ser funciones que sobre escriban, eliminen o amplíen algunas de las funciones que ya vienen en el sistema. No es muy recomendable pasarse poniendo funcione (ya que aumentarán las necesidades de recursos de la máquina) pero sí que es interesante tener en cuenta algunas de estas:

Añadir tu propio CSS en wp_nav_menu:

function custom_nav_class($classes, $item) {
  $classes[] = "custom-class";
  return $classes;
}
add_filter('nav_menu_css_class' , 'custom_nav_class' , 10 , 2);

Eliminar la versión de WordPress del RSS/Atom:

function remove_feed_generator() {
  return '';
}
add_filter('the_generator', 'remove_feed_generator');

Añadir un campo para Twitter y Facebook en la ficha del usuario, y mostrarlo en el listado de usuarios:

function add_contactmethods($contactmethods) {
  $contactmethods['twitter'] = 'twitter';
  $contactmethods['facebook'] = 'facebook';
  return $contactmethods;
}
add_filter('user_contactmethods','add_contactmethods',10,1);
function profile_links($actions, $user_object) {
  $actions['website'] = '<a href="'.$user_object->user_url.'">web</a>';
  $actions['facebook'] = '<a href="'.$user_object->facebook.'">fb</a>';
  $actions['twitter'] = '<a href="'.$user_object->twitter.'">tw</a>';
  return $actions;
}
add_filter('user_row_actions', 'profile_links', 10, 2);

Cambiar el color de las entradas en el panel de administración) según su estado:

function posts_status_color() {
?>
  <style>
  .status-draft { background: #FCE3F2 !important; }
  .status-pending { background: #87C5D6 !important; }
  .status-publish { /* por defecto */ }
  .status-future { background: #C6EBF5 !important; }
  .status-private { background: #F2D46F; }
  </style>
<?php
}
add_action('admin_footer','posts_status_color');

Enviar al resultado cuando sólo hay uno en una búsqueda:

function single_result() {
  if(is_search()) {
    global $wp_query;
    if($wp_query->post_count == 1) {
      wp_redirect(get_permalink($wp_query->posts['0']->ID ));
    }
  }
}
add_action('template_redirect', 'single_result');

Y por hoy ya está… próximamente algunos códigos más.

Desastres varios con WordPress

Creo que en las últimas semanas no me había encontrado con tan elevada cantidad de WordPress tan mal configurados. Y es que aunque WordPress es un gran sistema de gestión de contenidos (principalmente para blogs) en cuanto montas algo con cara y ojos y tienes más de 1.000 visitas al día el rendimiento del gestor de contenidos que viene por defecto (y con la configuración por defecto) es una castaña.

Estos últimos 3 meses me ha tocado documentar una base de infraestructura ideal para montar el software y, poco a poco, ir mejorándolo hasta llegar a lo que pensamos que puede ser una estructura ideal. No es fácil, ya lo digo, pero sin duda permite una escalabilidad que no habíamos podido tener.

Lo bueno de WordPress es que permite crecer de muchas maneras, y lleva elementos de serie (aunque no activados) que mejoran mucho la plataforma. Por ejemplo, la caché que lleva internamente es muy decente. Quizá la situación se complica cuando empezamos a meter plugins y otros elementos que lo complican en exceso.

Para empezar, algo tan básico como el fichero de configuración. No es suficiente con configurar la base de datos, sino que ejecutar la URL que te da las “claves aleatorias” para las cookies ya aumenta la seguridad muchísimo, porque, en caso de creer que te has dejado el ordenador con tu sesión abierta en cualquier lugar y correr peligro, tan sólo hay que regenerar estas claves para que se desloguee cualquier usuario y tenga que acceder y validar la clave si no la ha puesto. Otras cosas como cambiar el nombre del prefijo de la tabla por defecto (de wp_ a loquesea_) permitirá que ataques de inyección de SQL puedan quedar inútiles.

Aparte de cambiar el idioma define('WPLANG', 'es_ES'); también debemos activar la caché define('WP_CACHE', true); (que activará la caché interna del propio WordPress, sin necesidad de ningún plugin… aunque no es la mejor configuración, algo ayuda. Otras formas de evitar problemas es reducir las entradas históricas hasta eliminarlas define('WP_POST_REVISIONS', false); y activar un sistema que tenga autoguardado para que, mientras escribes tus entradas, se vaya guardando cada, por ejemplo, 120 segundos define('AUTOSAVE_INTERVAL',120);. Si tenéis un blog ya funcionando, podéis instalar, ejecutar, y desinstalar el plugin Better Delete Revision que os ayudará con la limpieza de basura antigua.

Ahora que ya tenemos la configuración base tocaría montar todo el sistema de estáticos para WordPress. Con esto te aseguras la velocidad de carga sin medida de las imágenes y otros elementos.

Y para acabar viene la reconfiguración de la caché. Personalmente utilizo y seguiré utilizando el wp-caché de Ricardo porque no es un plugin de caché, sino que reconfigura la caché interna del propio WordPress. En mi caso lo configuro para que cachee elementos al menos 24 horas. Una vez tenemos esto, ya lo últimos es meter una capa de Varnish por encima, con una configuración específica que nos hemos ido creando para este CMS (y que hace que, por ejemplo las cosas del panel de Administración no se cacheen, o que los comentarios no den errores…).

Para acabar, los plugins… la gente suele instalar “cualquier plugin” porque cree que está bien o hace lo que quiere, pero no todos los plugins están bien programados, y cosas que se pueden programar fácilmente (por ejemplo con códigos óptimos que hay por la red) se complican con plugins que hacen peticiones interminables a la base de datos y aumentan el tiempo de carga hasta los 2 segundos cuando deberían quedarse en menos de 1 segundo. Sin duda, cuando alguien me pide los plugins que uso o la posibilidad de añadir uno o cambiar por otro es una tarea bastante elevada que no es fácil de realizar.

Ahora, mi siguiente paso, es el de intentar eliminar las funciones deprecated y así reducir finalmente el consumo de memoria con elementos antiguos que no deberían usarse ya que existen funciones nuevas que las sustituyen…

Como decía, en estas últimas semanas me ha tocado optimizar cerca de 10 blogs (algunos de 100 visitas/día, otros de 15.000 visitas/día) con parte de estas herramientas… la velocidad de carga ha aumentado de forma exagerada y sin duda es un placer navegar por los sitios, cuando antes era algo insoportable.

PagedNoindex WordPress Plugin

Uno de los problemas que me encuentro con el All in One SEO Pack es que no permite que las paginaciones no se indexen, algo que puede generar ciertos problemas y que, personalmente no me gusta que haga.

Para solventar esto he creado un pequeño plugin para WordPress que detecta si es una pagina paginada y añade un meta-robots-noindex de forma que esa página no aparecerá en los motores de búsqueda como Bing o Google.

Tan sólo hay que subirlo y activarlo, ya que no requiere de ningún tipo de configuración ni nada parecido.

Puedes descargar el plugin desde aquí: PagedNoindex WordPress Plugin (versión 1.0 – 20110624).

Social Share Button WordPress Plugin

En muchas ocasiones he querido tener mi propio sistema para compartir en Twitter, Google PlusOne y Facebook, pero ninguna herramienta me daba exactamente lo que yo quería… así que me he montado este plugin para WordPress llamado Social Share Button.

Este sistema básicamente añade el botón de compartir en twitter (con el contador) el sistema de votación propio de Google (el Google +1 o Google PlusOne) y finalmente el botón de compartir en Facebook a través del famoso Me Gusta.

Este plugin incorpora un fichero de configuración que hay que editar antes de subirlo en el que se indican algunos elementos:

  • $social_lugar: Indicando 0 o 1 podemos hacer que el bloque aparezca encima o debajo del contenido.
  • $social_ancho: Es el ancho (en píxeles) de la columna donde está el contenido (entrada o página).
  • $social_idioma: El idioma en 2 letras ISO. Por ejemplo: es.
  • $social_fbidioma: El idioma en 4 letras (idioma_país). Por ejemplo: es_ES.
  • $social_twitter: Tu usuario de Twitter.
  • $social_fbancho: En principio no hace falta tocarlo, pero es el ancho de la parte de Facebook.
  • $social_fbsend: Si quieres que aparezca el botón “Enviar” de Facebook.
  • $social_fbcaras: Si quieres que aparezcan las caras de aquellos que han votado.
  • $social_fblike: Si quieres que aparezca el texto “Me gusta” o “Recomendar”.

NOTA: Si vas a activar este plugin, es muy recomendable que tengas activado el OpenGraphProtocol WordPress Plugin.

Puedes descargar el plugin desde aquí: Social Share Button WordPress Plugin (versión 1.0 – 20110624).

OpenGraphProtocol WordPress Plugin

El Open Graph Protocol es un sistema de meta-etiquetas que permite, de forma abierta, que algunos robots como por ejemplo los de Facebook) puedan recopilar información de tu página de una forma sencilla y así mostrar la información relevante en sus resultados. El ejemplo más claro sería el de compartir una URL en Facebook, que cuando lo haces te aparece un título, descripción e imagen (o te deja elegir).

Este plugin para WordPress básicamente lo que hace es crear esas meta-etiquetas de forma automática y tampoco es que permita ningún tipo de configuración. Simplemente lo subes, lo activas y hará su trabajo.

El sistema activa los datos de página y URL para todo el dominio, el tipo, la imagen (si es una imagen destacada, tomará esa, sino intentará encontrar la primera de la entrada y sino no elegirá ninguna) y lo mismo con la descripción.

Puedes descargar el plugin desde aquí: OpenGraphProtocol WordPress Plugin (versión 1.0 – 20110624).

Estáticos para WordPress

La verdad es que WordPress es un gran CMS y, sobre todo, muy extensible y configurable. En esta ocasión me gustaría enlazar una entrada que publiqué hace ya un tiempo en el que hablaba de los dominios sin cookies con la posibilidad de configurar WordPress para tener las imágenes separadas del dominio principal.

El objetivo de este sistema básicamente es separar lo que es la propia web de los contenidos estáticos que se pueden separar. En principio se podrían separar hasta los diseños (JS, CSS…) pero suele ser algo más complejo. Para empezar la idea es separar los contenidos que subimos a través del panel y que suelen estar en la carpeta /wp-content/uploads/.

Para comenzar lo que debemos tener es un dominio configurado para estáticos. En mi caso he usado el dominio javiercasares.com para el sitio web y el dominio javiercasares.net para los estáticos. Este dominio principalmente debe tener 2 cosas: ETag y Cookieless.

Lo primero que hemos de hacer es apuntar los contenidos al nuevo dominio. Para ello iremos a la opción Ajustes -> Multimedia y en la parte inferior tenemos las direcciones donde se almacenan los archivos. Los campos son los siguientes:

  • Guardar los archivos subidos en esta carpeta: Aquí deberemos poner la dirección completa donde se subirán los ficheros. Por ejemplo /home/estatico/uploads
  • Ruta URL completa a los archivos: Es la URL pública. Por ejemplo: http://javiercasares.net/uploads

Con esto conseguimos que a partir de este momento todos los ficheros que subamos se almacenen en esa ruta del servidor y que la URL pública sea esa.

Pero claro… ¿qué ocurre si ya teníamos un sitio web funcionando? Pues que una vez tengamos el dominio para estáticos configurado debemos hacer algunos pasos previos. El primero de ellos es copiar todos los ficheros de la antigua carpeta wp-content/uploads a la nueva carpeta. Al final del proceso, si queremos, podremos borrar los archivos originales, ya que no se volverán a utilizar.

El siguiente paso es el de actualizar todos los contenidos existentes en la base de datos. Hay que actualizar todos aquellos sitios en los que aún se llama a las direcciones URL / contenidos antiguos para que apunten a los nuevos. Para ello deberemos ejecutar las siguientes consultas en la base de datos:

UPDATE wp_posts SET post_content = REPLACE (post_content, 'http://javiercasares.com/wp-content/', 'http://javiercasares.net/');
UPDATE wp_posts SET guid = REPLACE (guid, 'http://javiercasares.com/wp-content/', 'http://javiercasares.net/');
UPDATE wp_postmeta SET meta_value = REPLACE (meta_value, 'http://javiercasares.com/wp-content/', 'http://javiercasares.net/');
UPDATE wp_commentmeta SET meta_value = REPLACE (meta_value, 'http://javiercasares.com/wp-content/', 'http://javiercasares.net/');
UPDATE wp_comments SET comment_content = REPLACE (comment_content, 'http://javiercasares.com/wp-content/', 'http://javiercasares.net/');
UPDATE wp_options SET option_value = REPLACE (option_value, 'http://javiercasares.com/wp-content/', 'http://javiercasares.net/');

La primera línea sustituye las direcciones en los contenidos (entradas y páginas), el segundo actualiza las direcciones de los adjuntos, el tercero si tenemos alguna imagen en los metadatos de las entradas, la cuarta y quinta es para los comentarios y la sexta hace referencia a las opciones del propio WordPress (por ejemplo para cabeceras o ficheros estándar que tengamos).

Con esto conseguiremos aumentar la velocidad de carga del sitio web hecho con WordPress además de permitir que el cacheo de las imágenes se haga de forma correcta si utilizas algún tipo de proxy-caché en algún sitio, ya que evitas tener Cookies y le añades los ETag que harán que se guarde la información completamente.

Si alguien necesita una optimización del rendimiento de su sitio web, desde Keep It Simple Lab ofrecermos un servicio de consultoría de WPO con el que podrá mejorar la velocidad de carga de su sitio (ya sea WordPress u otro sistema), aumentar la velocidad y reducir los recursos que se consumen.

Un par de trucos para WordPress con .htaccess

Muchas veces queremos hacer cosas en WordPress y buscamos plugins que pueden sobrecargar el sistema de forma absurda, pudiendo hacer mejoras gracias a unas pocas líneas del .htaccess.

Reducir spam en comentarios

En muchas ocasiones los robots de spam están tan mal hechos que no incluyen ningún tipo de referrer, algo que los usuarios por norma general sí que permiten… así que:

RewriteCond %{REQUEST_METHOD} POST
RewriteCond %{REQUEST_URI} .wp-comments-post\.php*
RewriteCond %{HTTP_REFERER} !.*dominio.com.* [OR]
RewriteCond %{HTTP_USER_AGENT} ^$
RewriteRule (.*) ^http://%{REMOTE_ADDR}/$ [R=301,L]

Evitar enlaces multimedia externos (hotlinking)

Gracias a esto puedes impedir que los sitios que te enlacen y usen tus imágenes reciban un bonito mensaje…

RewriteCond %{HTTP_REFERER} !^http://(.+\.)?dominio\.com/ [NC]
RewriteCond %{HTTP_REFERER} !^$
RewriteRule .*\.(jpe?g|gif|png)$ nohotlinking.png [L]

oEmbed, WordPress 2.9 y el editor de imágenes

Como muchos ya sabréis soy aficionado a tener una versión “alpha” de WordPress en mi blog personal, y de esa forma ir probando en tiempo real cómo es de estable el sistema antes de hacer las actualizaciones pertinentes en el resto de sitios de los que soy responsable… Y ahora que no creo que tarde mucho en salir esta nueva versión, me gustaría hacer un repaso de algunas características interesantes.

Antes de nada, he de decir que en muchos casos (no sé si es el autoguardado o qué) cuando voy a guardar un borrador o similar se pierde como el ID o algo y acaba fallando, total, que hay que volver a la lista y reabrir esa entrada (habiendo perdido el título y tags, normalmente).

El primero de los detalles que quiero comentar es el editor de imágenes que incluye. No es una barbaridad de editor, porque la verdad es que no supera al Scissors, pero es lo suficientemente sencillo y útil (sobretodo a la hora de redimensionar imágenes). Además, también permite gestionar cómo será el thumbnail por defecto de la entrada, que de eso ahora os hablo.

Wordpress 2.9 - Editor de Imágenes

Como decía, existe otra novedad que es la de los “thumbnails”. Se supone que se puede asignar una pequeña imagen por defecto a las entradas, creándola en base a una de las imágenes que subamos (como se puede ver en la imagen de arriba, en la parte inferior derecha). Para ello ha aparecido una nueva función:

the_post_image(); // Miniatura
the_post_image('thumbnail'); // Miniatura
the_post_image('medium'); // Mediana

Además de esto, quiero hacer referencia al oEmbed, que a muchos les va a ser muy útil, aunque todavía estoy investigando al 100% cómo funciona. La idea era que se utilizasen unos tags específicos, pero parece que se puede poner una dirección URL directa (y seguro que aparecerán plugins que ayuden a ello).

Por ejemplo, si ponemos una dirección de Flickr, la imagen debería aparecer automáticamente, sin necesidad de indicar el código HTML correspondiente (el <img src…> de toda la vida, vaya).

http://www.flickr.com/photos/juancasares/3562950871/

Si se pone esa dirección, a mi, personalmente, ahora mismo me falla la vista previa, como si no pudiera acceder a la imagen…

Según la documentación de Flickr, el código que habría que usar realmente es:

http://flickr.com/services/oembed?url=http://www.flickr.com/photos/juancasares/3562950871/&format=json&maxwidth=200

En este caso se puede omitir el “format”, y el “maxwidth”, si no se indica, es el que se haya configurado en las opciones del WordPress (que hay una pestaña donde se puede configurar esto).

Los parámetros que soporta el oEmbed son:

  • url: que es la dirección del elemento a incrustar (obligatorio)
  • maxwidth: el ancho máximo del objeto.
  • maxheight: la altura máxima del objeto.
  • format: el formato de respuesta

A parte de Flickr, también podríamos incrustar vídeos de Youtube:

Como comentaba antes, simplemente poniendo una dirección como la siguiente debería funcionar, aunque por ahora me falla y no carga la página… de todas formas, el código correcto sería:

http://www.youtube.com/oembed?url=http://www.youtube.com/watch?v=HJEoNtN7j04

Algunos de los proveedores que ofrecen ya el servicio de oEmbed son:

  • Clearspring Widgets: http://widgets.clearspring.com/widget/v1/oembed/
  • Flickr: http://www.flickr.com/services/oembed/
  • Hulu: http://www.hulu.com/api/oembed.{ext}
  • My Opera: http://my.opera.com/service/oembed
  • oohEmbed: http://oohembed.com/oohembed/
  • Poll Everywhere:http://www.polleverywhere.com/services/oembed/
  • Qik: http://qik.com/api/oembed.{ext}
  • Revision3: http://revision3.com/api/oembed/
  • Viddler: http://lab.viddler.com/services/oembed/
  • Vimeo: http://www.vimeo.com/api/oembed.{ext}
  • YouTube: http://www.youtube.com/oembed

Por cierto, para los geeks que quieran implementar esto del oEmbed en su propio CMS o servicio, existe una librería en PHP además de soporte PHP.

Nota final: parece que para que todo funcione correctamente hay que instalar este plugin llamado oohEmbed y se supone que, junto a WordPress 2.9, la cosa funciona… (aunque a mi me sigue sin ir).

Lo que hace un índice

Como ayer comenté, a veces las decisiones de actualizar software y tal quizá no sean las mejores, aunque lo flipante es que una gilipollez consiga tirarte una máquina y llevar locos a los técnicos de un ISP.

Estos días ando ayudando a migrar un proyecto que estaba antes en HTML con PHP que llamaba y tal, y que ya era ingestionable, y decidimos pasarlo a SQL, recuperando del HTML la información importante y como CMS decidimos utilizar WordPress.

El problema nos lo hemos encontrado al tener más de 21.000 posts y una base de datos que ocupa más de 250 megas. La cuestión es que no tenía sentido que se cayera cada dos por tres el servidor, el Apache, el mySQL y todo en reacción en cadena… Al final, más movimientos han hecho que los del ISP se quejen diciendo que se había jodido la máquina…

Total, al final, como el tema estaba en que había muchas “query_slow” he pedido que activen el log y me he puesto a mirar que era… y la solución ha sido una de las mayores tonterías del mundo… algo que ha hecho que una máquina con 4 procesadores que iba al 95% de media antes haya pasado a un 50% de CPU, y que los 2 GB de memoria que estaba antes al 98% ocupados hayan quedado al 60%.

¿Cómo es posible que un campo de la base de datos de WordPress con el que se ordenan cientos de consultas no esté indexada? Pues sí, ha sido mano de santo.

Tan sólo hay que ejecutar esto en el SQL y se solucionan algunos problemas, sin que afecte a la configuración inicial de WordPress. Por cierto, cuidado con el “prefijo” de la tabla, que según como lo hayáis dado de alta puede o no ser el mismo.

ALTER TABLE wp_posts ADD INDEX (post_date)

En fin, si alguien que utiliza o desarrolla WordPress me puede decir porqué eso no está indexado, se lo agradecería enormemente… porque estoy pensando en avisar para que se incluya de serie… porque en grandes cantidades de información esto muere. Básicamente es que el “listar entradas” del panel, hace un ORDER BY post_date

Los cambios de hora y WordPress

La última vez que hubo un cambio de hora, me crucé unos cuantos correos con anieto2k para ver si había una solución a algo que, en mi caso, supone dedicarle un rato y acordarse de muchas contraseñas: cambiar el huso horario a WordPress.

Y es que aunque los servidores cambia de hora de forma automática, el que no lo hace es WordPress. Creo recordar que hace un tiempo ya incluyó 2 campos de hora en su sistema, uno GMT y el otro con el horario establecido… el problema es que WordPress no te cambia la hora, lo que significa que hay que cambiarla “a mano”.

Hace un rato he tenido que entrar en cada uno de los que gestiono (directa o indirectamente) y que superan los 15, e ir cambiándoles, dentro de la opción de configuración general:

Lo que más me gusta es el mensaje: Desafortunadamente, tienes que actualizar manualmente para el horario de verano. No sabemos porque, pero se arreglará en el futuro.

NOTA: Si tienes algún post programado para el futuro a partir del cambio de fecha, recuerda revisar la hora, ya que es probable que te aparezca una hora por delante o por detrás de la hora en la que lo habías programado…