paging results in Drupal

Paginating the results in Drupal is incredible incredible easy. You just have to remember the two "magic functions":


  • pager_query($sql, $count);
  • theme('pager',10);


pager_query substitutes the typical db_query. Just something like that: 


  • // $resource = db_query($sql);  // -> old sentence without pager
  • $resource = pager_query($sql, $count); // -> pager


Then, we simple come back to the function that is called by our hook_menu, and we change:

  • return theme('list_products')


  • return theme('list_products') . theme('pager',10);


It couldn't be easier, could it? :-). In fact it is harder to undertand the documentation and the different howtos and tutorials which you can find than the process itself.

Theming you module

Docs are not allways the best part in programming languages, frameworks or CMS. Sometimes you try to make something and you find problems, just because poor documentation.

It's my situation just now. I was trying to create tpl.php files for a module, and it is really easy... if you follow exactly all the steps.

First, hook_menu:




 * Implements hook_menu().


function mymodule_menu() {

$items = array();



* Category reviews section 


$items['reviews'] = array(

'title'             => 'Bounty reviews',

'description'       => 'Show review categories.',

'page callback'     => 'listofProducts',

  'page arguments'    => array('bounty_settings'),

'access callback'   => 'user_access',

'access arguments'  => array('administer site configuration'),

'type'              => MENU_NORMAL_ITEM,

'file'              => 'includes/bounty_reviews.inc',



return $items;




Secondly, you could think that just creating the listofProducts should be enought. Well, not at all, you need the theme hook, to show the content using the tpl.php of you choose:



 * Implements hook_theme().


function mymodule_theme($existing, $type, $theme, $path){

$path = drupal_get_path('module', 'mymodule'); // . '/templates';

// ADD THE templates DIRECTORY

$path = $path . '/templates'; 

return array(

// as in 'theme('verbose_method',...)

'main_reviews' => array(

'template' => 'main_page_reviews',

'path' => $path,

'variables' => array('forums' => NULL, 'topics' => NULL,'parents' => NULL, 'tid' => NULL, 'sortby' => NULL, 'forum_per_page' => NULL),






And, ending with the magic:



 * List of  reviewable products



function listofProducts(){

$output = theme('list_products');

return $output;


That's all. If you forget the _theme hook you can be struggling for hours, just receiving a beauty WSOD (White Screen Of the Death) and no more information.

You wellcome :-).


Minimal Apache2 modules for Drupal

This days i've been having problems with my server, until i arrived to a point on I was considering seriously disable Apache and install ngnix, a light server I am using in my laptop and some small projects.

The point is that I don't have noticed a real big performance increment in my laptop (difficult with a few users). Anyway, having to install a new server, disable Apache, tuning everything to work correctly is a good challenge... unless you are at the doors of taking a plane and don't want to be all the trip thinking about the server...

Solution? Ok, let's tuning the Apache2 server, very easy because where are only going to use a2dismod to disable the modules and a2enmod to activate if they give us some error... Easy, right?

Let's go, this is my minimal (by now) apache modules list:

actions.conf  alias.conf  authn_file.load authz_host.load  dir.load    fcgid.load  mime.load  php5.load  suexec.load

actions.load  alias.load  authz_groupfile.load dir.conf fcgid.conf  mime.conf php5.conf  rewrite.load

You can disable the rest with a2dismod [MODULENAME], for example:

a2dismod cgi

I recommend you to restart your server once disabled. If apache cannot restart, enable the module again with a2enmod [MODULENAME] and try again the restart.

I have to say that last week I've been having a lot of problems... The last thing I did was to tune in that way Apache... and simply magic, sites load incredibly fast with this simply modification.

Now, I can fly withour worries :-).


Fatal error: require_once() [function.require]: Failed opening required sites/all/ modules/feeds_xpathparser/ FeedsXPathParser

After installing all the updates and changing the core of drupal (main files), you could find this error doing the upgrade (opening upgrade.php).

It's a problem specified here: http://drupal.org/node/868532

Well, simply disable the feeds modules, all, ignore by now the errors and proceed with the upgrade. No errors, right?

You can now put again your website online and proceed to solve the problem (previous link) with feeds, with without having to wait to your users :-).


Error 500 in Drupal (invite module)

Error 500 in your Drupal? Don't panic.... well, a little maybe, but be sure you'll find a way to solve it.

open your index.php in root Drupal and add:


ini_set('display_errors', '1');

Reload the Error 500 page and, evoilá:

Fatal error: Call to undefined function invite_page_title() in /[.....]/httpdocs/includes/menu.inc on line 

This is saying that there is a problem with a module. In my case, I disabled invite, and seems to cause problems. Before the show php errors trick I was blind, but I disabled several modules and started to have problems, so I had no way to know which one were giving us problems and, so the, how to solve it.

Ok, if this is the scenario (not able to even login in your site to disable modules), then drush is simply magic. Install it and:

drush --uri=website.com enable invite

try now. If the error persists, it is probably that it has changed and now it shows you another module or another kind of problem. That's is, then, another story :-).

Sometimes you'll need to clear your cache or make some other operations, only availabe via admin interface... well, not exactly, drush also can help you, for example, with a "clean drush" For more information visit: http://groups.drupal.org/node/28088


Drupal slow when saving nodes (content, comments, admin ...)

Drupal slow when saving nodes (content, comments, admin ...)? Maybe the problem is really simple, try to deactivate some modules that you don't use. It is common to test modules that you finally don't use in your production server. Search for them and deactivate, they take a lot of memory, even if you think you are not using them.




varnish in Drupal howto

Installing Varnish is really simple and easy to perform, and is very unlikely to give you problems with your server that any other more complex methods could give you, like using light servers or so. Probably you cannot compare both performances, but to start improving you Drupal server is a good point from where start.

Let's go:

1. Install Varnish. In Ubuntu / Debian is as easy as:

sudo apt-get install varnish

2. Install Varnish module in your Drupal:


Be sure not to make the START=no mistake.

3. Start your Varnish server: sudo /etc/init.d/varnish start

Go to admin/settings/varnish in your Drupal and select enabled.

4. Copy the Varnish Control Key which you´ll find in /etc/varnish/secret (you'll need to be root or read with "sudo vim /etc/varnish/secret").

5. Enjoy :-)

Drupal: available variables in a concrete place, web, ...

Tipycal scenario. Imagine you need to know which variables yo need in a concret place of your site, say /blog, a node or a view. Very easy, simple add a block, for example at your foot if available in your theme, with php input availabe, and this code:

<?php  print '<pre>';  var_dump(get_defined_vars());  print '</pre>';?>

Now, make it only available for your role, for example, and place it where you prefer (foot for example).

Comparar y buscar perfiles de usuarios en Drupal

Drupal tiene varios módulos bastante buenos que permiten crear perfiles de usuarios a base de crear nodos (o contenidos) y asociarlos a tu perfil.

El módulo que se suele usar para esto en Drupal 6 en Content Profile, aunque en Drupal 7 ha cambiado un poco la cosa, es algo más compleja a primera vista, pero en general los cambios son a mejor mediante el uso de "Entities" y el módulo Profile2.

Puedes montarte, por poner un ejemplo inocente, una red social en la que los usuarios tienen su propio muro, información de su perfil, gustos, viajes hechos, el vino que les gusta, fecha de nacimento, ... lo que se os ocurra.

Genial, verdad? Ahora imaginaros que en esa red social "imaginaria" vamos a querer cruzar datos para, "por ejemplo", buscar amigos. Muy útil en una red social, verdad? Verdad que sería interesante no sólo mostrar usuarios sin más, sino mostrar únicamente aquellos usuarios que tengan coincidencias con tu perfil?

Con Drupal y el módulo views pueden hacerse maravillas sin tener que tocar una sólo linea de mysql y/o php... ahora bien, si queremos hacer algo más complejo, como lo es precisamente el cruzar datos de un perfil y encontrar coincidencias en otro... Drupal es fantástico pero no hace magia... todavía ;-).

Bien, solución? Muy "simple", expresiones regulares + mysql + tipos de contenido. Las expresiones regulares son algo así como la navaja suiza del programador, no entiendes su potencia hasta que realmente no te pones a trabajar con ellas.

La opción de usar un tipo de contenido es porque podemos crear un nodo específico para cada usuario en el que metamos un código php específico para ese tipo de nodos, y con rules, por ejemplo, hagamos que cuando un usuario se registra en la red ese nodo se crea automáticamente.

El contenido de dicho nodo como decía lo dirigiremos desde el node-TIPODECONTENIDO.tpl.php. La magia está simplemente en cargar desde la plantilla los datos del usuario "owner" usando el campo $node->uid). Con esos datos haremos ahora consultas sobre sobre los campos "nodeprofile" que pertenecen a dicho usuario, almacenamos los datos que nos interesen en un campo de texto, y lanzamos una consulta contra todos los usuarios obteniendo los mismos datos, pero de cada usuario.

Con esos datos en variables distintas "sólo" queda jugar con expresiones regulares, e ir almacenando, por ejemplo en un Array, los usuarios cuya coincidencia sea la que estamos buscando.

La coincidencia de la que os hablo puede ser exacta, lo que en la mayoría de los casos no tiene sentido, o "parcial". Ahora queda jugar con expresiones regulares en php para encontrar esa "coincidencia parcial" en los perfiles de usuario.

Usar de esta forma los tipos de contenido y los templates .tpl.php de Drupal es probablemente una aberración, pero es una solución rápida sin necesidad de tener que programar un módulo, cosa que por otra parte es muy sencillo.

Mucha teoría, verdad? Los próximos días pondré algún ejemplo en forma de código... y si habéis sido buenos probablemente en forma de módulo :-).


migrar contenido de drupal a drupal con mysql y phpmyadmin

Atención: lo siguiente es una administración de Drupal de guerrilla. No os recomiendo llevarla a cabo a menos que realmente sepáis que lo necesitáis y sabéis lo que estáis haciendo. Igualmente, un backup antes de poneros en harina es altamente aconsejable. Si pierdes datos o la base de datos entera no me hago responsable de las consecuencias, lo que vas a leer a continuación es sólo apto para no cardíacos, y por tanto si sigues alguna de mis indicaciones lo haces por tu cuenta y riesgo :-).

Caso expuesto: migrar contenido de un drupal a otro, siendo el segundo un Drupal en marcha (más de 6.000 nodos y unos 1.000 usuarios) y el primero con unos 600 nodos y otros 500 usuarios aprox.

Primer paso, backup:

  • mysqldump --opt -uUSER -pPASS BBDDaMigrar  > BBDDaMigrar-BACKUP.sql
  • mysqldump --opt -uUSER -pPASS BBDDaMigrar  > BBDDaRecibirMigracion-BACKUP.sql


Segundo paso, migrar los nodos (del Drupal a migrar, se entiende):

  • CREATE TABLE node2 LIKE  node; #creamos una tabla sobre la que jugar
  • INSERT node2 SELECT * FROM node;


Repetimos con node_revisions:

  • CREATE TABLE node_revisions2 LIKE node_revisions;
  • INSERT node_revisions2 SELECT * FROM node_revisions;

Y con los tipos de contenido que tengamos a medida:

    • CREATE TABLE content_type_empresa2 LIKE content_type_empresa;
    • INSERT content_type_empresa2 SELECT * FROM content_type_empresa;


La tabla node_type no contiene nid ni datos de este tipo que tengamos que adaptar, solo una descripción por nombre del tipo de contenidos. Por lo tanto, no hace falta migrarla, simplemente nos aseguramos de que existe el tipo de contenido en la base de datos o el Drupal que va a recibir los nodos (page, blog, ... los estándar y cualquier tipo nuevo que hayamos creado nosotros o el admin del sitio).

Ahora volcamos estas tablas en el Drupal que vaya a recibir los datos:

primero, backup de las tablas:

  • mysqldump -uUSUARIOMYSQL -pPASSMYSQL nombreBBDDOrigen node_revisions2 > node_revisions2.sql
  • mysqldump -uUSUARIOMYSQL -pPASSMYSQL nombreBBDDOrigen node2 > node2.sql
  • mysqldump -uUSUARIOMYSQL -pPASSMYSQL nombreBBDDOrigen node_revisions2 > node_revisions2.sql


segundo, volcamos el backup en el Drupal receptor.

  • mysql -uUSUARIOMYSQL -pPASSMYSQL nombreBBDDDestino < node_revisions2.sql
  • mysql -uUSUARIOMYSQL -pPASSMYSQL nombreBBDDDestino < node2.sql

Ahora tenemos los nodos en la base de datos final. Sin embargo los datos nuevos tienen ids que coincidirán con los que ya existan en Drupal (en el receptor, se entiende). Solución? Contar los nodos que ya existen y sumar ese número al nid de los nodos que hemos traido a la base de datos. Por ejemplo, en mi caso teníamos unos 6000 y pico nodos. El nid nuevo será 7.000 + nid.

No nos preocupamos por nada más ya que Drupal se encargará de asignar a los nuevos nodos los ids correctos, teniendo en cuenta los nuevos nodos que han aparecido en la base de datos.

Vamos allá:

  • UPDATE  `node2` SET  `nid` = `nid` + '7000';
  • UPDATE  `node_revisions2` SET  `vid` = `vid` + '7000';
    UPDATE  `node2` SET  `uid` = `uid` + '500'  ;

    • UPDATE  `node_revisions2` SET  `nid` = `nid` + '7000'  ;


idem con content_..._empresa, o los tipos de contenido que tengamos "a medida":

  • UPDATE  `content_type_empresa` SET  `nid` = `nid` + '7000';
  • UPDATE  `content_type_empresa` SET  `vid` = `vid` + '7000';
  • UPDATE  `content_type_empresa` SET  `uid` = `uid` + '500'  ;


cuidado con esto último. El nodo pertenece a un usuario de la BBDD anterior, con lo que también hay que, tanto en node, noderevisions y content, modificar el nuevo usuario.

Bien, en este punto ya estamos listos para volcar estas tablas en su sitio definitivo...o más bien para concatenar las tablas que ya tenemos con estas nuevas.

Primero, una vez más, backup de lo que tengamos:


  • mysqldump -uUSUARIOMYSQL -pPASSMYSQL nombreBBDDOrigen node_revisions > node_revisions.sql
  • mysqldump -uUSUARIOMYSQL -pPASSMYSQL nombreBBDDOrigen node > node.sql


Segundo, pasamos concatenamos los nuevos nodos, que es justamente el proceso inverso con el que empezamos todo este "lio":


    • INSERT node SELECT * FROM node2;
    • INSERT node_revisions SELECT * FROM node_revisions2;
    • INSERT content_type_X SELECT * FROM content_type_X2;



Y, si no ha habido ninguna incidencia, tenemos una bonita base de datos con el número de nodos total justamente igual a la suma de los nodos de ambas webs en Drupal, ni más ni menos, y con id's que son:

para la base de datos "receptora", los nid son los mismo,

para la base de datos que "aluniza" en esta base de datos, el nid que tuviera antes más la constante que hayamos elegido como precaución (en nuestro caso 7.000).

En otro post tocaremos el tema de las taxonomías, y cómo podemos migrarlas sin que se produzcan colisiones a la vez que los posts no pierdan sus respectivas clasificaciones.