Ofrecer sugerencias en tu WordPress usando opensearch

Creo que para ciertos blogs es muy útil ofrecer la opción de añadir OpenSearch para que la gente puede realizar búsquedas en nuestro blog. Algo también bastante útil es que nos ofrezca sugerencias de búsquedas (tal y como hace Google). Para ello tan sólo hay que añadir una opción al XML de OpenSearch y modificar nuestro functions.php.

En el fichero XML deberemos añadir la siguiente etiqueta:

Y añadir xmlns:suggestions="http://www.opensearch.org/specifications/opensearch/extensions/suggestions/1.1" a la etiqueta inicial OpenSearchDescription

Yo en este caso he preferido usar una URL amigable, sobre todo para practicar con el wp_rewrite, pero se podría hacer perfectamente con una variable con parámetros.

Una vez cambiado el opensearch.xml deberemos modificar el functions.php, para lo cual tendremos que coger el término que se quiere sugerir y buscar entre las categorías y tags y entre los títulos de los posts para así mostrar una unión de ambos. Las categorías se ordenarán por el número de veces que aparece y los posts por fecha descendente.

add_filter('init','suggestion_init');
add_filter('query_vars','suggestion_insertMyRewriteQueryVars');
add_filter('rewrite_rules_array','suggestion_rewrite');

// Acciones iniciales
function suggestion_init(){
  // Reescribe las reglas
  global $wp_rewrite;
  $wp_rewrite->rewrite_rules();

  // Obtiene el termino a buscar
  $req = explode('/', substr($_SERVER['REQUEST_URI'], 1), 2);
  if ($req[0] == 'suggestion') {
    $result = wp_cache_get( 'suggestion_'.$req[1] );
    if ( false == $result ) {
      global $wpdb;
      $list = array();
      // Recupera las 4 categorias/tags que coincidan
      $res = $wpdb->get_results("select name from $wpdb->terms t, $wpdb->term_taxonomy tx where name like '%".$req[1]."%' and t.term_id = tx.term_id group by name order by count desc limit 4");
      foreach ($res as $item) $list[] = $item->name; 
      // Recupera las 4 anotaciones que coincidan   
      $res = $wpdb->get_results("select post_title from $wpdb->posts where post_title like '%".$req[1]."%' order by ID desc limit 4");
      foreach ($res as $item) $list[] = $item->post_title;
      // Devuelve en formato JSON     
    	$result = json_encode(array($req[1], $list));
    	wp_cache_set( 'suggestion_'.$req[1], $result );
    } 

    echo $result;
    exit();
  }
}

// Permite que WP acepte un nueva parametro en la query de la URL
function suggestion_insertMyRewriteQueryVars($vars) {
    array_push($vars, 'suggestion');
    return $vars;
}

// Reescribe la regla
function suggestion_rewrite($rules)
{
	$newrules = array();
	$newrules['suggestion/([^/]+)/(.*)$'] = 'index.php?suggestion=$matches[1]';
	return $newrules + $rules;
}

En el código he añadido caché, porque es altamente recomendable, puediendo usar el plugin WP File Cache. También debo decir que me encontré con el problema del timeout que tiene Firefox para esperar la respuesta para la sugerencia, muy pequeño para mi servidor, por lo que si quieres modificarlo, busca el fichero nsSearchSuggestions.js y modifica el valor de _suggestionTimeout.

Nuevos posts rápidos

Últimamente no ando muy sobrado de tiempo, por lo que no posteo tanto como me gustaría, además, hay pocos temas que considere interesantes como para hacer un post, pero si son lo suficientemente interesantes para realizar un post rapidillo, a ser posible automático.

Es por ello que me he creado un plugin para WordPress, que cuando tenga tiempo lo puliré y publicaré, que me permite postear directamente desde Google Reader usando lo de “Enviar a”, vamos que con una llamada a una URL tipo http://sentidoweb.com/[path_seguridad]/[token]/${title}%20${source} publicaré directamente en mi blog, así podré pasaros posts que considere interesantes.

Crear un formulario de contacto para un theme de WordPress

¿Para que crear un formulario de contacto en un theme si ya existe algún plugin que te lo hace todo y muy bien?. Fácil, porque cuando subes un theme a wordpress.org, no te deja meter plugins, y si lo quieres vender, no puedes meter mil instrucciones para instalarlo, lo lógico es que copie el theme y poco más.

El tutorial explica paso a paso cómo crear la página, hacer que WordPress la entienda, crear el formulario de contacto, validación por jQuery haciendo uso de un plugin y envío del email.

How to create a built-in contact form for your WordPress theme

Vía / DZone

Laboratorio: postear en WordPress mediante GTalk o Jabber (mejorado)

Hace tiempo hice un script para PHP que permitía postear en WordPress usando Jabber (por ejemplo GTalk). Ahora he mejorado un poco el script para que admita poner categorías (si no las hay, las crea) y subir imágenes mediante una URL (ajustándolo a un ancho máximo).

Existen distintas palabras claves para separar los distintos elementos del post dentro del texto que se envía: titulo, contenido, tags, categorias e image. Las distintas secciones se separan con ‘##’ para diferenciarlas unas de otras y se separarán por dos puntos ‘:’ formando pares clave:valor. Un ejemplo para escribir en el IM sería el siguiente:

titulo:Titulo del post##contenido:Lorem Ipsum... con todo el HTML que querramos##tags:etiqueta1, etiqueta2, etiqueta3##categorías:Categoria1,Categoria2#image:http://servidor.com/ruta/imagen.png

El código principal es el siguiente:

$e

";'), explode("\n", $contenido))); } if (isset($image)) { $img_content = file_get_contents($image); $im = imagecreatefromstring($img_content); $w = imagesx($im); $h = imagesy($im); $imgtype = exif_imagetype($image); if ($w > $max_width) { $image_p = imagecreatetruecolor($max_width, intval($h*$max_width/$w)); imagecopyresampled($image_p, $im, 0, 0, 0, 0, $max_width, intval($h*$max_width/$w), $w, $h); ob_start(); imagepng($image_p); $img_content = ob_get_contents(); ob_end_clean(); $imgtype = IMAGETYPE_PNG; $w = $max_width; $h = intval($h*$max_width/$w); } $imgname = "img".time().image_type_to_extension($imgtype); $f = new xmlrpcmsg('metaWeblog.newMediaObject', array(php_xmlrpc_encode($blog_usuario), php_xmlrpc_encode($blog_usuario), php_xmlrpc_encode($blog_contraseña), php_xmlrpc_encode(array('name'=>$imgname, 'bits'=>new xmlrpcval($img_content, 'base64')))) ); $c=new xmlrpc_client($blog_xmlrpc_path, $blog_url, $blog_puerto); $c->setDebug(0); $r=&$c->send($f); if(!$r->faultCode()) { $v=$r->value(); $datos = simplexml_load_string($v->serialize()); $url = $datos->xpath('//member/name[. ="url"]/following-sibling::*/string'); $contenido = ''.$contenido; } else { return "Error a la hora de subir la imagen: $image [".$r->faultString()."]"; } } //$contenido .= mb_convert_encoding($contenido, 'UTF-8'); $f = new xmlrpcmsg('wp.getUsersBlogs', array(php_xmlrpc_encode($blog_usuario), php_xmlrpc_encode($blog_contraseña)) ); $c=new xmlrpc_client($blog_xmlrpc_path, $blog_url, $blog_puerto); $c->setDebug(0); $r=&$c->send($f); if(!$r->faultCode()) { $v=$r->value(); $datos = simplexml_load_string($v->serialize()); $blogid = $datos->xpath('//member/name[. ="blogid"]/following-sibling::*/string'); $blogid = is_array($blogid) ? (string) $blogid[0] : (string) $blogid; $f = new xmlrpcmsg('metaWeblog.newPost', array(php_xmlrpc_encode($blogid), php_xmlrpc_encode($blog_usuario), php_xmlrpc_encode($blog_contraseña), php_xmlrpc_encode(array('title'=>$titulo, 'description'=>$contenido, 'mt_keywords'=>$tags)), php_xmlrpc_encode(1)) ); $c=new xmlrpc_client($blog_xmlrpc_path, $blog_url, $blog_puerto); $c->request_charset_encoding = 'UTF-8'; $c->setDebug(0); $r=&$c->send($f); if($r->faultCode()) { return "Ha habido un error al intentar crear un nuevo post [".$r->faultString()."]"; } else { $datos = simplexml_load_string($r->serialize()); $postid = $datos->xpath('//value/string'); $postid = is_array($postid) ? (string) $postid[0] : (string) $postid; $f = new xmlrpcmsg('metaWeblog.getPost', array(php_xmlrpc_encode($postid), php_xmlrpc_encode($blog_usuario), php_xmlrpc_encode($blog_contraseña)) ); $c=new xmlrpc_client($blog_xmlrpc_path, $blog_url, $blog_puerto); $c->setDebug(0); $r=&$c->send($f); if($r->faultCode()) { return "Ha habido un error al intentar recuperar información sobre el post insertado [".$r->faultString()."]"; } else { $datos = simplexml_load_string($r->serialize()); $permalink = $datos->xpath('//member/name[. ="permaLink"]/following-sibling::*/string'); $permalink = is_array($permalink) ? (string) $permalink[0] : (string) $permalink; $title = $datos->xpath('//member/name[. ="title"]/following-sibling::*/string'); $title = is_array($title) ? (string) $title[0] : (string) $title; if (isset($categorias)) { $f = new xmlrpcmsg('mt.getCategoryList', array(php_xmlrpc_encode($postid), php_xmlrpc_encode($blog_usuario), php_xmlrpc_encode($blog_contraseña)) ); $c=new xmlrpc_client($blog_xmlrpc_path, $blog_url, $blog_puerto); $c->setDebug(0); $r=&$c->send($f); if(!$r->faultCode()) { $datos = simplexml_load_string($r->serialize()); $catsblog = $datos->xpath('//struct'); foreach(explode(',', $categorias) as $cat) {$cats[$cat] = null;} foreach($catsblog as $cat) { foreach($cats as $_cat=>$val) { if (strtolower((string) $cat->member[1]->value->string) == strtolower($_cat)) { $cats[$_cat] = (string) $cat->member[0]->value->string; } } } foreach($cats as $cat=>$val) { if (!$val) { $f = new xmlrpcmsg('wp.newCategory', array(php_xmlrpc_encode($postid), php_xmlrpc_encode($blog_usuario), php_xmlrpc_encode($blog_contraseña), php_xmlrpc_encode(array('name'=>$cat, 'slug'=>str_replace(' ', '_', strtolower($cat)), 'parent_id'=>1, 'description'=>''))) ); $c=new xmlrpc_client($blog_xmlrpc_path, $blog_url, $blog_puerto); $c->setDebug(0); $r=&$c->send($f); if(!$r->faultCode()) { $datos = simplexml_load_string($r->serialize()); $catid = (string) $datos->xpath('//int'); $cats[$cat] = $catid; } else { return "Ha habido un error a la hora de crear la categoría $cat"; } } } foreach($cats as $val) { $catlist[] = array('categoryId'=>$val); } $f = new xmlrpcmsg('mt.setPostCategories', array(php_xmlrpc_encode($postid), php_xmlrpc_encode($blog_usuario), php_xmlrpc_encode($blog_contraseña), php_xmlrpc_encode($catlist)) ); $c=new xmlrpc_client($blog_xmlrpc_path, $blog_url, $blog_puerto); $c->setDebug(0); $r=&$c->send($f); if($r->faultCode()) { return "Hubo un error a la hora de modificar las categorías del post"; } } else { return "Ha habido un error al intentar recuperar las categorias del blog"; } } return "Se ha publicado '$title': $permalink"; } } } else { return "Ha habido un error al intentar recuperar información sobre el blog [".$r->faultString()."]"; } } //Use XMPPHP_Log::LEVEL_VERBOSE to get more logging for error reports //If this doesn't work, are you running 64-bit PHP with < 5.2.6? $conn = new XMPPHP_XMPPOld($jabber_host, $jabber_puerto, $jabber_usuario, $jabber_contraseña, 'xmpphp', $jabber_host, false, XMPPHP_Log::LEVEL_ERROR); $conn->autoSubscribe(); $conn->useEncryption(false); try { $conn->connect(); while(!$conn->isDisconnected()) { $payloads = $conn->processUntil(array('message', 'presence', 'end_stream', 'session_start')); foreach($payloads as $event) { $pl = $event[1]; switch($event[0]) { case 'message': if (trim($pl['body']) == '') break; $conn->message($pl['from'], $body=post($pl['body']), $type=$pl['type']); if($pl['body'] == 'quit') $conn->disconnect(); if($pl['body'] == 'break') $conn->send(""); break; case 'presence': // print "Presence: {$pl['from']} [{$pl['show']}] {$pl['status']}\n"; break; case 'session_start': //print "Empezamos\n"; $conn->getRoster(); $conn->presence($status="Asonesss jefeeeeeee!"); break; } } } } catch(XMPPHP_Exception $e) { echo 'ERROR:'; die($e->getMessage()); }

Podéis bajaros el código aquí.

Importar RSS en WordPress sin usar un plugin

Buen tutorial que explica cómo importar los contenidos de un RSS en nuestro blog sin tener que usar un plugin, que sinceramente, hace bastante busqué un plugin que lo hiciera y no encontré nada que me llegara a gustar.
El tutorial es bastante completo, dividido en tres partes: importar usando WP de forma sencilla y de forma más avanzada, para lo cual utiliza las funciones de WP que hacen uso de Magpie. O utilizando SimplePie, para lo cual no es necesario WP.
Import and Display RSS Feeds in WordPress
Vía / Script & Style

Plugin WordPress para usar Sphinx

Interesante plugin que nos permite usar Sphinx en nuestro WordPress, aunque siendo realistas, dudo mucho que el 5% de los blogs que usen WordPress puedan necesitar el potencial de Sphinx.

Ofrece todas las características propias de Sphinx (entre ellas su rapidez) y además añade las siguientes:

  • Permite buscar en páginas, posts y comentarios
  • Permite excluir posts, comentaios o páginas de las búsquedas
  • Muestra los comentarios en la página de resultados
  • Busca en páginas no protegidas con contraseña
  • Busca unicamente en comentarios aprobados
  • Modifica el title de la página de resultados según la búsqueda
  • Muestra el top de palabras buscadas
  • Muestra las ultimas palabras buscadas

WordPress Sphinx Plugin

Crear un plugin para WordPress con su propia tabla

Interesante artículo en el que nos explican cómo crear un plugin de wordpress usando su propia tabla, algo que no suele necesitarse porque para almacenar datos propios se usan las “options”, pero en algún momento podemos necesitarlo.

Nos explica paso a paso qué hay que hacer:

  • Declarar la función y las variables globales que se necesitan
  • Darle un nombre a nuestra tabla y usar el prefijo de WP
  • Comprobar que la tabla no existe y si no, crearla
  • Añadir la funcionalidad a WordPress
  • Añadir datos a la nueva tabla

Create a Plugin With Its Own Custom Database Table

Convertir WordPress en un CMS

Aunque como usuario me gusta WordPress (aunque cada vez un poquito menos), como desarrollador no me gusta demasiado (por no decir casi nada), pero no quita que su puesto se lo tiene bien ganado y que a veces es imposible no tener que usarlo.
Si además de las funcionalidades de WP, necesitas algo más que te puede aportar un CMS genérico, te puede venir bien este tutorial que explica en pocos pasos cómo convertir WordPress en un CMS.
Para ello el autor mueve el blog a la carpeta /blog y en la home de la página crea una página principal en la que se mostrará un portfolio y los resúmenes de sus diferentes trabajos (teniendo cada trabajo una página individual).
Los cambios incluyen la creación de archivos nuevos para el theme, que recoge los resúmenes de cada apartado del portfolio, los cuales son páginas estáticas que cuelgan de la página principal del portfolio.
Seguro que existe algun plugin que te lo permite hacer, pero la explicación es muy buena y la idea la podemos aprovechar para otras necesidades.
WordPress as CMS tutorial
Vía / dzone

Laboratorio: postear en WordPress mediante GTalk o Jabber

Hace tiempo hablaba de una librería para trabajar con Jabber desde PHP y me preguntaban si se podía usar para realizar un cliente y realizar acciones con él. Pues he usado esta librería para crearme un cliente de jabber que espere mensajes y los publique en WordPress, para lo cual también he necesitado la librería phpxmlrpc.

Yo el ejemplo lo he hecho con DreamHost y la posibilidad que ofrece de crear un servidor Jabber, claro que también se puede hacer mediante GTalk.

Lo primero es tener dos cuentas: una para el cliente y otra para ti. Cuando ya las tengamos, deberemos autorizar la una a la otra para que puedan enviarse mensajes. Esto es la parte más chapuza ya que hay que hacerlo con clientes tipo Gtalk o Pidgin.

Tan solo nos queda instalar el script en nuestro servidor o en nuestro ordenador (aunque casi mejor en un servidor) y configurarlo. Se copia en el servidor y se edita el fichero orejas.php y modificar los siguientes valores:

  • $blog_usuario: nombre del usuario del blog
  • $blog_contraseña: contraseña del usuario del blog
  • $blog_url: url del blog de WordPress
  • $blog_xmlrpc_path: path al script xmlrpc de WordPress
  • $blog_puerto: puerto del blog (lo más seguro es que no haya que modificarlo)
  • $post_tags: etiquetas por defecto del post que se va a crear
  • $post_separador: separador para diferenciar en el mensaje entre título, contenido y etiquetas
  • $post_titulo_defecto: título por defecto del post
  • $jabber_host: servidor de Jabber, para GTalk creo que es gtalk.google.com
  • $jabber_usuario: usuario de jabber
  • $jabber_contraseña: contraseña del usuario de jabber
  • $jabber_puerto: puerto del servidor de jabber (lo más seguro es que no haya que modificarlo)

Para postear en WP habrá que mandar un mensaje al cliente con el siguiente formato:

titulo##contenido##etiqueta1,etiqueta2,...,etiquetan

Contenido admite HTML y retornos de carro que serán convertidos en párrafos. Si no se quiere indicar título o etiquetas, pues se puede escribir el contenido solamente. El separador ## es modificable. Cuidado si vais a escribir retornos de carro, porque si pulsas sólo INTRO te enviará el mensaje.

Una vez enviado el mensaje, el script posteará en WP y devolverá la URL del nuevo post.

Supongo que se pueden hacer más cosas y mejor, pero para lo que yo lo necesito me basta y me sobra.

Descarga: orejas