view counter

Creación de un módulo Drupal

Hoy vamos a ver cómo crear un módulo drupal sencillito. Como ejemplo vamos a escribir nuestro propio módulo, algo que sea útil: un "feedback".

Actualización 2010/01/09: Existía un error en hook_validate que he corregido. Debe devolver un form y el error debe establecerse sobre uno de los componentes del formulario (por ejemplo, "message")

Actualización 2010/05/03: Añado el código completo al final del artículo.

En este tutorial nos vamos a centrar en drupal 6. Para usar otro drupal, basta mirarse la API de cada función.

Tras probar varios, para la edición recomiendo kate.

Directorios y ficheros

Los módulos deben colgar a partir de la ruta /etc/drupal/6/sites/default/modules. Allí crearemos un directorio con el nombre de nuestro módulo. En este caso, "feedback": /etc/drupal/6/sites/default/modules/feedback.

Será en este directorio donde vayan nuestros ficheros. Para el ejemplo, tan sólo vamos a crear 3 ficheros: feedback.info, feedback.module y feedback.install. El primero de los ficheros sirve para decirle a drupal de qué va nuestro módulo; el segundo contendrá toda la lógica; y el tercero servirá para crear la base de datos.

Diciéndole a Drupal que estamos aquí

Crearemos el archivo feedback.info. Su contenido es el siguiente:

; $Id$
name = "Feedback"
description = "Proporciona un formulario para solicitar mejoras."
core = 6.x

Habitualmente, la gente de drupal suele comenzar por un comentario con el ID del repositorio. De esta manera, es fácil identificar la versión del módulo.

A continuación viene el nombre, tal cual se mostrará en la ventana de administracción. Conviene usar algo corto.

La descripción puede ser algo más larga. Aparecerá también en la ventana de administracción, y nos dará una idea sobre para qué sirve el módulo. Podemos usar hasta varias líneas

El "core" hace referencia a la versión de drupal para la que se construye el módulo. Como vamos a hacer algo para drupal 6, el valor será "6.x".

A parte de estas 3 palabras clave que son obligatorias ("name", "description" y "core"), hay varias opcionales, como "package", "dependences", ... que están más allá del objetivo de este tutorial. Vean la documentación para más información.

Tened cuidado con las tildes y las eñes, ya que pueden causar problemas. Si guardáis en UTF-8, os ahorraréis quebraderos de cabeza. Además, si encerráis las cosas entre comillas dobles (como he hecho), podréis usar varias líneas ;)

Creación de la base de datos

Suele ser buena política comenzar los nombres de las tablas con el nombre del módulo; así nos aseguramos que no se van a chocar con otros módulos. Así, vamos a crear la tabla "feedback_messages", para lo que crearemos el fichero feedback.install:

<?php
function feedback_schema ()
{
  $schema['feedback_messages'] = array
  (
    'description' => t('Tabla para mensajes de retroalimentacion'),
    'fields' => array
    (
      'id' => array
      (
        'description' => t('Identificador de mensaje'),
        'type' => 'serial',
        'unsigned' => TRUE,
        'not null' => TRUE,
      ),
      'uid' => array
      (
        'description' => t('Identificador del usuario que realiza el feedback'),
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => FALSE,
      ),
      'message' => array
      (
        'description' => t('Mensaje de feedback'),
        'type' => 'text',
        'not null' => TRUE,
      ),
      'indate' => array
      (
        'description' => t('Fecha en la que se crea el comentario'),
        'type' => 'datetime',
        'not null' => TRUE,
      ),
    ),
    'primary key' => array('id'),
  );
  return $schema;
}


function feedback_install() {
  // Create my tables.
  drupal_install_schema('feedback');
}

function feedback_uninstall() {
  // Drop my tables.
  drupal_uninstall_schema('feedback');
}
?>

Nota importante: En los ejemplos, voy a cerrar los el tag que indica que hemos entrado en modo PHP. Sin embargo, en nuestros módulos es muy importante que los dejemos abiertos. Es decir: usaremos "<?php", pero no "?>".

Aquí hemos creado una cosa que se llama "hook" y que veremos más adelante. En concreto, hemos usado el hook_schema, hook_install y hook_uninstall.

Existen algunas limitaciones. Para comenzar, Drupal utiliza un tipo de tabla de MySQL que no soporta Foreign Keys, por lo que no tenemos que preocuparnos por eso: nada más que las tablas y los campos.

Quizá os llame la atención la función "t". Sirve para indicarle a Drupal que es un texto traducible, y, si encuentra la traducción, lo mostrará traducido. Conviene poner las claves en inglés, que es el idioma por defecto para Drupal, pero esa norma me la he saltado a la torera.

Por lo demás, no creo necesario comentar el archivo: como cada apartado tiene su comentario, creo que se explica sólo.

Creación de la lógica

Ahora vamos con lo más difícil: La lógica del módulo.

Una norma básica: Todas las funciones de nuestro módulo deben comenzar por el nombre de nuestro módulo. Si queremos crear una función estática (invisible desde fuera), antecederemos una barra baja ('_').

En la documentación veremos muchas referencias a "hook". No es el Capitán Garfio... Son funciones que Drupal espera encontrar en nuestro código (aunque no todas son obligatorias), es decir: puntos de entrada a nuestro módulo.

Veamos un ejemplo de hook: hook_help. Así, de paso, proporcionamos un poco de ayuda a nuestro módulo.

<?php
/**
* Implements hook_help().
*/

function feedback_help ( $path, $arg )
{
  $output=''; // para construir la salida
  switch ( path )
  {
    case 'admin/help#feedback':
      $output .= '<p>' . t('Módulo que permite la inserción de mensajes de feedback.') . '</p>';
      break;
  }
  return $output;
}
?>

Nota: Vuelvo a recordar que los ficheros del módulo contendrán el <?php, pero no el ?>.

Con esa función en nuestro feedback.module tenemos asegurado que cuando alguien acceda a admin/help#feedback podrá ver la ayuda.

Para más información, la página de hook_help.

Permisos

Veamos ahora quién puede usar nuestro módulo.

Por un lado, queremos que cualquier usuario pueda rellenar un formulario, que será lo que después veremos desde un usuario administrador. Así que tenemos dos tipos de permiso: "send message" y "view message". El primero será útil por si sólo queremos el feedback de usuarios autenticados. Pensad que luego tendremos que asignar estos permisos a algunos roles. El nombre de los permisos puede coincidir con otros, pero no creo que pase nada, porque van identificados contra nuestro módulo (es posible que exista alguno especial para ver si se tienen privilegios de administrador, etc.).

Para crear los permisos, tenemos otro hook, el hook_perm:

<?php
/**
* Implements hook_perm().
*/

function feedback_perm ()
{
  return array ('send message', 'view messages');
}
?>

Nota: Aún a riesgo de ser pesao, os recuerdo que nuestro código tendrá un <?php al principio, pero no un ?> al final.

Nota 2: En algún sitio leí que los comentarios para los hooks se recomiendan que sean como éstos que estoy poniendo.

Como véis, no tiene mayor complicación. Copiar y pegar en nuestro feedback.module

Más información en hook_perm y también aquí.

Bloques

Nuestro módulo aún no hace nada. Ahora vamos a declarar dos bloques: Uno para que el Administrador del sitio pueda colocar donde quiera un enlace al formulario (que luego crearemos) y otro para que el Administrador pueda decidir quién y dónde pude verse si hay algún mensaje o no.

La función hook_block (seguro que ya os lo esperábais) tiene tres parámetros:

  • $op, que puede valer "list", "view", "save" o "configure", dependiendo de la operación solicitada. En nuestro caso, como vamos a lo fácil, sólo contemplaremos "list" y "view".
  • $delta, que sirve para identificar el identificador de bloque.
  • $edit, usado para la operación "save", por lo que nos olvidamos de él.

<?php
/**
* Implementation of hook_block().
*/

function feedback_block ( $op = 'list', $delta = 0, $edit = array() )
{
  if ( $op == "list")
  {
      $blocks = array();
      $blocks[0]["info"] = t('Feedback');
      $blocks[1]["info"] = t('New Feedbacks');
      return $blocks;
  }
  else if ( $op == "view" )
  {
      $content = '';
      $block = array();
      switch ( $delta )
      {
        case 0:
          $block['subject'] = t('Feedback');

          $options = array( "attributes" => array("title" => t("Sends a feedback message") ) );
          $link = l( t("New Feedback"), "feedback/message", $options );
          $content .= '<div class="link">' . $link . "</div>";
          break;
        case 1:
          $block['subject'] = t('Feedback Messages');

          $options = array( "attributes" => array("title" => t("Shows feedback messages") ) );
          $title = t("There are @total new feeds", array ( '@total' => _feedback_count() ) );
          $link = l( $title , "feedback/adminmessages", $options );
          $content .= '<div class="link">' . $link . "</div>";
          break;
      }
      $block['content'] = $content;
      return $block;
  }
}
?>

NOTA: ¿Adivináis? Un "<?php", ningún "?>".

Vamos a ver esto, que tiene mucha tela.

La parte de "list" no tiene mucha complicación: es un array que devuelve en la posición 0 el bloque para usuarios y en la posición 1, el de administradores. Se le pasan los títulos y en paz.

La parte de "view" depende de si estamos en el bloque 0 (usuarios) o en el bloque 1 (administradores). Ambos van a crear un enlace ($link) a unas páginas que trataremos más adelante. Además, le añaden un título molón mediante $options. Para que queden chulos se utiliza la clase "link". Y... Bueno, en el caso de los administradores nos interesa saber cuántos feedbacks nuevos hay, por lo que llamamos a la función _feedback_count(), que debe darnos el número de feeds nuevos.

Como es facilita, vamos con la función _feedback_count():

<?php
/** Devuelve el número de feeds creados en la última semana
*/

function _feedback_count ()
{
  $query = "SELECT count(id) as total from {feedback_messages} where datediff( now(), indate ) < 7";
  $queryResult =  db_query ( $query );
  $result = db_fetch_object ( $queryResult ) ;
  return $result->total;
}
?>

NOTA: Una vez más: Un "<?php", ningún "?>".

Bueno, ya tenemos un ejemplo (pequeñito) de consulta SQL :D

Aquí nos dejamos pendiente el manejar las direcciones de los enlaces. Esto se verá en los siguientes apartados.

Pero... Antes que nada, ¡ vamos a probar lo poco que tenemos !

Probando que no os engaño

Si todo está en su sitio, deberíamos poder ver los módulos. Vamos a Drupal, Administer->Site Building->Modules, buscamos nuestro modulito, que estará en la sección "others" (sección por defecto, ya que no hemos establecido un "package" en el .info) y lo activamos.

Guardamos la configuración.

¡¡ Y ya está funcionando !!

...

¿Que no veis nada? ¡Pues claro que no! Vamos con los bloques: Administer->Site Building->Blocks, buscamos "New Feedbacks" y "Feedback" y los colocamos en algún sitio, por ejemplo en la "Right sidebar", y guardamos.

Tachaaaaaaan!!!

Si no hemos hecho algo mal (vosotros o yo), deberíais ver vuestros dos fabulosos bloques.

Manejando direcciones

En el apartado anterior nos dejamos pendiente el manejo de direcciones. Para esto hay otro hook, el hook_menu:

<?php
/**
* Implementation of hook_menu().
*/

function feedback_menu ( )
{
  $items = array();

  $items['feedback/message'] = array
  (
    'title' => t('Feedback'),
    'page callback' => 'feedback_message',
    'access arguments' => array('send message'),
    'type' => MENU_CALLBACK,
  );
  $items['feedback/adminmessages'] = array
  (
    'title' => t('Feedback Admin'),
    'page callback' => 'feedback_admin',
    'access arguments' => array('view messages'),
    'type' => MENU_CALLBACK,
  );
  return $items;
}
?>

Nota: Todos a una: "un <?php, pero ningún ?>".

Con esto le estamos contando a Drupal qué función es la que nos va a generar la página a mostrar en ese link.

Así que volvemos a dejar cosas en el tintero: ahora tenemos que crear las funciones feedback_message y feedback_admin.

Si os dais cuenta, hemos rellenado "access arguments". Estos son los permisos necesarios para poder acceder a ese link. Si el usuario que trata de acceder no tiene esos permisos, se le mostrará la página de que no tiene acceso (ojo, que el administrador tiene todos los permisos).

Creación de un formulario

Vamos con el formulario de inserción de un feed. Comenzamos por la función que nos dejamos pendiente:

<?php
function feedback_message ()
{
  $content = '';
 
  $content .= drupal_get_form ( 'feedback_message_form' );

  return $content;
}
?>

Y con eso, delegamos en la función feedback_message, que es un formulario. Al ser un formulario, tiene "cosas especiales". Por ejemplo, tiene hooks. Así podemos tener el hook_validate y el hook_submit, que se ejecutarán para validar y enviar el formulario, respectivamente. Venga, no hay dolor; vamos con las 3 a la vez:

<?php
function feedback_message_form ()
{
  $form = array
  (
    'feedback' => array
    (
      '#type' => 'fieldset',
      '#title' => t( 'Feedback' ),
      'message' => array ( '#type' => 'textarea', "#description"=>"Write here your message" ),
      'submit' => array ( '#type' => 'submit',  '#value' => t('Submit'),  ),
    ),
  );
  return $form;
}

function feedback_message_form_validate ( $form, &$form_state )
{
  $message = $form_state['values']['message'];
  if ( $message == '' )
    form_set_error( 'message', t('Message cannot be empty.'));
  return $form;
}

function feedback_message_form_submit ( $form, &$form_state )
{
  global $user;
  $userid = NULL;
  if ( $user )
    $userid = $user->uid;
  $message = $form_state['values']['message'];

  $query = "INSERT into {feedback_messages} ( uid, message, indate ) values ( %d, '%s', now() ) ";
  $queryResult = db_query ( $query, $userid, $message );

  if ( db_affected_rows() )
    drupal_set_message ( t ( "Thank you for your feedback." ) );
  else
    form_set_error ( $form, t( "An error has happened. Your feedback has not been sent." ) );
}
?>

Nota: ... <?php ... ?> ...

No hay mucho que comentar aquí... Que la función del formulario devuelve un array, que hook_submit y hook_validate se tienen que llamar igual que la función del formulario pero con las coletillas _submit y _validate, que si "validate" lanza el form_set_error entonces no se lanza el submit y... poco más.

Como el submit no ha redireccionado a otra página, aparecerá de nuevo la antigua.

Tablas

Vamos a hacer algo muy cutre: una tabla enorme con todos los feeds. Por no ser tan sumamente cutres, haremos que sea ordenable si pinchamos en las cabeceras :D

<?php
function feedback_admin ()
{
  $content = '';

  $header = array
  (
    array('data' => t('Date'), 'field' => 'indate', 'sort' => 'desc'),
    array('data' => t('User'), 'field' => 'name'),
    array('data' => t('Message'), 'field' => 'message'),
  );

  $query = "SELECT u.name, fm.indate, fm.message FROM {feedback_messages} fm, {users} u WHERE fm.uid=u.uid";
  $queryResult =  db_query ( $query );

  $rows = array ();
  while ( $message = db_fetch_object ( $queryResult ) )
  {
    $row = array ();
    $row['name'] = $message->name;
    $row['indate'] = $message->indate;
    $row['message'] = $message->message;
    $rows[] = $row;
  }

  $content .= theme_table($header, $rows);
  return $content;
}
?>

Nota: ... <?php ... ?> ...

$header tiene las cabeceras y son el nexo con los campos. El while transforma los resultados en un vector de arrays y, al llamar a theme_table, Drupal sabe cómo tiene que renderizar eso, así que nos lo pinta todo mono.

Si alguien llega alguna vez a leer hasta aquí y lo pide, continuaré el tutorial, diciendo cómo mejorar esta función. Hay distintas cosas que podemos hacerle: paginar los resultados, poner sólo un trozo del mensaje ( mensaje completo en otra página/en la misma pero arriba del todo), formulario de búsquedas, etc.

Enlaces

Creación de módulos para drupal
Escribir ficheros .info
Tipos de datos para el .install

Licencia

Este documento se puede distribuir bajo licencia FDL y el código bajo licencia GPL v3 o posterior, a su elección.

Y fin

Espero que lo encontréis útil. Para problemas, errores, unas pizzas: http://www.magmax.org

Código

Puedes encontrar el código de este módulo (listo para descomprimirse en /etc/drupal/6/sites/default/modules/) justo aquí.

Si sólo lo quieres ver, aquí tienes:

feedback.info

; $Id$
name = "MagMax Feedback"
description = "Proporciona un sistema de feedbacks fácil para drupal"
core = 6.x

feedback.install

<?php
/*
Copyright 2009 Miguel Ángel García Martínez <miguelangel.garcia@gmail.com>

  'Feedback' is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

  'Feedback' is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
along with 'Feedback' (maybe in file "COPYING"); if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/



function feedback_schema ()
{
  $schema['feedback_messages'] = array
  (
    'description' => t('Tabla para mensajes de retroalimentacion'),
    'fields' => array
    (
      'id' => array
      (
        'description' => t('Identificador de mensaje'),
        'type' => 'serial',
        'unsigned' => TRUE,
        'not null' => TRUE,
      ),
      'uid' => array
      (
        'description' => t('Identificador del usuario que realiza el feedback'),
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => FALSE,
      ),
      'message' => array
      (
        'description' => t('Mensaje de feedback'),
        'type' => 'text',
        'not null' => TRUE,
      ),
      'indate' => array
      (
        'description' => t('Fecha en la que se crea el comentario'),
        'type' => 'datetime',
        'not null' => TRUE,
      ),
    ),
    'primary key' => array('id'),
  );
  return $schema;
}


function feedback_install() {
  // Create my tables.
  drupal_install_schema('feedback');
}

function feedback_uninstall() {
  // Drop my tables.
  drupal_uninstall_schema('feedback');
}
?>

feedback.module

<?php
/*
Copyright 2009 Miguel Ángel García Martínez <miguelangel.garcia@gmail.com>

  'Feedback' is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

  'Feedback' is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
along with 'Feedback' (maybe in file "COPYING"); if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

/**
* Implements hook_help().
*/

function feedback_help ( $path, $arg )
{
  $output=''; // para construir la salida
  switch ( path )
  {
    case 'admin/help#feedback':
      $output .= '<p>' . t('Módulo que permite la inserción de mensajes de feedback.') . '</p>';
      break;
  }
  return $output;
}

/**
* Implements hook_perm().
*/

function feedback_perm ()
{
  return array ('send message', 'view messages');
}

/**
* Implementation of hook_block().
*/

function feedback_block ( $op = 'list', $delta = 0, $edit = array() )
{
  if ( $op == "list")
  {
      $blocks = array();
      $blocks[0]["info"] = t('Feedback');
      $blocks[1]["info"] = t('New Feedbacks');
      return $blocks;
  }
  else if ( $op == "view" )
  {
      $content = '';
      $block = array();
      switch ( $delta )
      {
        case 0:
          $block['subject'] = t('Feedback');

          $options = array( "attributes" => array("title" => t("Sends a feedback message") ) );
          $link = l( t("New Feedback"), "feedback/message", $options );
          $content .= '<div class="link">' . $link . "</div>";
          break;
        case 1:
          $block['subject'] = t('Feedback Messages');

          $options = array( "attributes" => array("title" => t("Shows feedback messages") ) );
          $title = t("There are @total new feeds", array ( '@total' => _feedback_count() ) );
          $link = l( $title , "feedback/adminmessages", $options );
          $content .= '<div class="link">' . $link . "</div>";
          break;
      }
      $block['content'] = $content;
      return $block;
  }
}

/**
* Implementation of hook_menu().
*/

function feedback_menu ( )
{
  $items = array();

  $items['feedback/message'] = array
  (
    'title' => 'Feedback',
    'page callback' => 'feedback_message',
    'access arguments' => array('send message'),
    'type' => MENU_CALLBACK,
  );
  $items['feedback/adminmessages'] = array
  (
    'title' => 'Feedback admin',
    'page callback' => 'feedback_admin',
    'access arguments' => array('view messages'),
    'type' => MENU_CALLBACK,
  );
  return $items;
}

function feedback_message ()
{
  $content = '';
 
  $content .= drupal_get_form ( 'feedback_message_form' );

  return $content;
}

function feedback_message_form ()
{
  $form = array
  (
    'feedback' => array
    (
      '#type' => 'fieldset',
      '#title' => t( 'Feedback' ),
      'message' => array ( '#type' => 'textarea', "#description"=>"Write here your message" ),
      'submit' => array ( '#type' => 'submit',  '#value' => t('Submit'),  ),
    ),
  );
  return $form;
}

function feedback_message_form_validate ( $form, &$form_state )
{
  $message = $form_state['values']['message'];
  if ( $message == '' )
    form_set_error( $form, t('Message cannot be empty.'));
}

function feedback_message_form_submit ( $form, &$form_state )
{
  global $user;
  $userid = NULL;
  if ( $user )
    $userid = $user->uid;
  $message = $form_state['values']['message'];

  $query = "INSERT into {feedback_messages} ( uid, message, indate ) values ( %d, '%s', now() ) ";
  $queryResult = db_query ( $query, $userid, $message );

  if ( db_affected_rows() )
    drupal_set_message ( t ( "Thank you for your feedback." ) );
  else
    form_set_error ( $form, t( "An error has happened. Your feedback has not been sent." ) );
}


function feedback_admin ()
{
  $content = '';

  $header = array
  (
    array('data' => t('Date'), 'field' => 'indate', 'sort' => 'desc'),
    array('data' => t('User'), 'field' => 'name'),
    array('data' => t('Message'), 'field' => 'message'),
  );

  $query = "SELECT u.name, fm.indate, fm.message FROM {feedback_messages} fm, {users} u WHERE fm.uid=u.uid";
  $queryResult =  db_query ( $query );

  $rows = array ();
  while ( $message = db_fetch_object ( $queryResult ) )
  {
    $row = array ();
    $row['name'] = $message->name;
    $row['indate'] = $message->indate;
    $row['message'] = $message->message;
    $rows[] = $row;
  }

  $content .= theme_table($header, $rows);
  return $content;
}

/** Devuelve el número de feeds creados en la última semana
*/

function _feedback_count ()
{
  $query = "SELECT count(id) as total from {feedback_messages} where datediff( now(), indate ) < 7";
  $queryResult =  db_query ( $query );
  $result = db_fetch_object ( $queryResult ) ;

  return $result->total;
}
?>

Comentarios

Hola, muchisimas gracias por

Hola, muchisimas gracias por este tutorial,

he realizado todos los pasos y al acceder haciendo click desde los links de los bloques (feedback/message o feedback/adminmessages) me aparece "page not found". Adicionalmente descarge el modulo que se ofrece en el tutorial ( http://www.magmax.org/files/feedback1.tgz ), habilite el modulo y los bloques, doy clic en los links y sucede lo mismo "page not found". ¿que podra ser?¿sera la version de Drupal? (estoy usando la 6.17)

Page not found...

Pues esto que comentas es extraño, ya que todo el mundo dice que el tutorial funciona a la primera...

Prueba a hacer un update. Para ello, pones la url de tu sitio /update.php . Vete a la parte administrativa y comprueba si hubo algún error. También deberías comprobar que se ha limpiado la caché (Administrar->Rendimiento->Limpiar los datos de la caché).

Otra opción es que el problema esté en la propia configuración del sitio (o que se me haya colado algo que genera ese error, que también puede ser). Puedes probar a meter a mano el enlace. Por ejemplo, para probar en este site si funciona un enlace de los de "feedback", bastaría con probar con la dirección http://www.magmax.org/drupal/feedback/message (como ves, la dirección del site seguida de lo que se indica en el hook_menu).

Por favor, prueba estas soluciones y me cuentas.

¡¡ Un saludo !!

Hola, ante todo te reitero

Hola, ante todo te reitero mis modestos agradecimientos por tan buen tutorial.

Y respecto al problema creo que faltaba limpiar los datos de chache. Digo "creo" por que la verdad por el momento había dejado el tutorial para revisar mas adelante y tome otros tutoriales donde limpié el chache, y ahora encuentro que trabaja con normalidad el modulo Feedback, asi que especulo que siempre habia funcionado el código, pero por alguna razon el cache no dejaba ver correctamente el módulo.

de nuevo muchas gracias por el tiempo y esfuerzo en ofrecer esta información al publico!!!

Gracias!!

Pues muchas gracias.

Si te ha gustado, puedes probar la segunda parte del tutorial de drupal, que creo que te puede interesar.

Un saludo!!

Llamar modulo desde navegador

Muy buenas, ante todo agradecerte este magnífico aporte que nos ha sacado a más de uno las castañas del fuego... ale después de enjabonarte un rato me gustaría preguntarte como narices se hace para acceder al menú feedback desde el navegador como si de un node se tratase... yo intento ?q=feedback pero no encuentra pagina alguna y lo mismo es que estoy haciendo algo mal... ¿podrías sacarme una vez más las castañas del fuego? desde ya agradecerte el trabajo realizado.

Llamar módulo desde navegador

Aquí hay dos cuestiones.

Por un lado: Para acceder como si fuera un node... debería ser un node. Hacer eso es bastante complejo y, en este caso, nos daría un montón de ventajas que no necesitamos. Por si quieres investigar más sobre el tema, te recomiendo que busques por "CCK". De todos modos, tengo pensado hacer, un día de estos, un tutorial sobre cómo usar esto (temo que tardare muuuuucho en sacarlo, aunque hay maneras de animarme).

Por otro lado: Cuando intentas "?q=feedback" no te encuentra nada porque... no hay nada. Si has copiado el ejemplo tal cual, y miras en la función feedback_menu, verás que hemos registrado "feedback/message" y "feedback/adminmessages". Así que tienes dos opciones:

  1. Cambiar la función feedback_menu, con el fin de que busque en "feedback" en lugar de "feedback/message" (aunque no lo recomiendo, ya que si no te encuentra "feedback/adminmessages" se irá a "feedback")
  2. Buscar en "?q=feedback/message" en lugar de "?q=feedback".

Por cierto, he aprovechado para arreglar un bug, aunque el bug sigue en el .zip.

Te animo a que sigas con la segunda parte del tutorial drupal, y estate atento, porque algún día sacaré 4 partes más, pero es que no tengo mucho tiempo ahora (hay formas de animarme :D).

Un saludo.