Cambrico.net

Distribuir contenido
Actualizado: hace 54 mins 8 segs

Más vistas con argumentos en Drupal: jugando con las taxonomías

Agosto 5, 2008 - 18:31

Una de las grandes ventajas de las vistas con argumentos en Drupal es el juego que te permiten con las taxonomías, de forma bastante simple, podemos hacer que se nos muestre información relacionada con ciertas categorías, y complicándolo un poquito más, podemos realizar cosas como las que pregunta cdp en este comentario:

Quiero hacer una vista que al hacer click sobre un nodo me muestre todos los nodos que tengan los mismos tags que el nodo sobre el que se ha hecho click. He creado el vocabulario, pero por ahora no he conseguido crear una vista que me muestre los nodos comunes a los vídeos. ¿Solucionaría mi problema una vista con argumentos?

Es decir, en una vista de tipo bloque, mostrar todos los nodos que compartan tags con el que estamos visualizando. Esto también se puede hacer con las vistas con argumentos

Nota: Para estos ejemplos he creado varios nodos con ciudades, cada ciudad pertenece a un país y tiene un idioma, ambas características marcadas por la taxonomía.

ejemplo simple

En este ejemplo, se muestra cómo hacer una vista con argumentos para que muestre los nodos pertenecientes a la taxonomía que se le pasa por parámetro.

un poco más complejo

Complicándolo un poquito más, podemos hacer una vista de tipo bloque que, a partir del nodo actual, muestre todos aquellos con los que comparta taxonomía.
Modificar las vistas de esta forma requiere algunos conocimientos de PHP.

Utilizaremos este código como "Argument Handling Code", del que podés encontrar más información en el handbook de drupal


// Utilizamos arg(1) para recoger el parámetro 1 de la url, es decir, el nodo.
// Por ejemploen la url node/12, arg(0) sera "node" y arg(1) será 12.
$nid = arg(1);
//Utilizamos la función taxonomy_node_get_terms, que nos devuelve un array
// con todos los términos que tiene el nodo.
$terms = taxonomy_node_get_terms($nid);
$url = array();
// Recorremos el array de términos del nodo, capturando los ids
foreach($terms as $id=>$term) {
$url[] .= $id;
}
// Generamos una lista de ids separados por +, 1+2+3
$url = implode("+",$url);
// Finalmente le pasamos al primer argumento $args[0] la lista separada por +
$args[0] = $url;
// Y usamos un segundo argumento para excluir el propio nodo
$args[1] = $nid;
return $args;

Bloque con los detalles de los artículos técnicos

Agosto 2, 2008 - 17:24

Oskar me sugirió en este comentario mostrar en algun sitio de los artículos sobre drupal los detalles sobre módulos, versiones, etc y me ha parecido una muy buena idea, y mi aproximación final fue crear una subcategoría para poder gestionar la información de cada post.
Me gusta mucho el bloque flotante que tienen en lullabot en alguno de sus posts para mostrar el contenido relacionado y he intentado hacer algo parecido. A la derecha de este texto lo podéis ver (si entráis en el detalle, en portada no se muestra).

Voy a intentar contaros cómo lo he hecho.

en el interfaz de drupal

A través del interfaz de drupal y el módulo taxonomía del core, he creado un vocabulario aparte llamado "drupal" para poner la información relacionada. Como opciones he seleccionado Jerarquía simple para poder tener términos relacionados padres-hijos y Selección múltiple para poder seleccionar más de un término por artículo.
En este caso he utilizado los términos padres como títulos de la sección (pej. módulos o versión) y los hijos son los detalles del bloque (views, 5x, ...).
La selección múltiple tiene el inconveniente de que es necesario crear el término a través del interfaz y no lo puedes hacer desde el mismo post. Se podrían utilizar módulos como el Hierarchical Select para resolver esto.

en el template.php

Aquí es donde viene "lo gordo". En el fichero template.php de nuestro theme, podemos modificar las variables que se pasan a los ficheros de phptemplate tpl.php, de esta forma, podemos hacer que las variables $links, $content o $terms entre otras muestren la información que queramos.
Para conseguir que este segundo vocabulario se mostrara como yo quería, era necesario modificar la variable $terms, para que mostrara un div con la información extra solamente si ésta existe. Para acceder y modificar las variables de phptemplate, se usa el array $vars, en este caso $vars['terms'].
En los comentarios del código aclaro el funcionamiento:

/**
* Override or insert PHPTemplate variables into the templates.
*/
function _phptemplate_variables($hook, $vars) {
if ($hook == 'node') {
    $node = $vars['node'];
    // Solamente para los nodos de tipo blog, que es el tipo
    // de contenido que estoy utilizando
    if ($node->type == 'blog') {
      // Selecciono los términos del vocabulario número 2,
      // que es el que he creado para este bloque
      $sql = "SELECT t.tid, vid, name
              FROM term_data t
              JOIN term_node n ON (t.tid = n.tid)
              WHERE vid = 2
              AND nid = %d
              ORDER BY weight";
      $result = db_query($sql, $node->nid);
      // En este bucle hago una transformación a un array más
      // manejable para crear el <div>. de estructura
      // $terms['padre']['id_del_termino']['datos']
      while ($data = db_fetch_object($result)) {
        // Función de la taxonomía que devuelve los padres
        // de un término dado
       $parent = taxonomy_get_parents($data->tid);
        $parent = array_shift($parent);
        $terms[$parent->name][$data->tid]['vid'] = $data->vid;
        $terms[$parent->name][$data->tid]['tid'] = $data->tid;
        $terms[$parent->name][$data->tid]['name'] = $data->name;
        $terms[$parent->name][$data->tid]['padre'] = $parent->name;
        $terms['parent'][$parent->name] = $parent;
      }
      // Si había términos del vocabulario y se ha rellenado el array
      if ($terms) {
       // Solamente se muestra en el detalle del nodo, y no en portada
        if (!$vars['teaser']){
          $output .= '<div class="terms">';
          // 13 es el número del vocabulario drupal en mi blog,
          // Ya que he creado un vocabulario extra exclusivo para drupal
          // Lo pongo así directamente.
          $output .= "<ul><li>".l('drupal','taxonomy/term/13')."</li></ul>";
          $output .= "</div>";
          $output .= "<div class = 'term-drupal'>";
          foreach($terms['parent'] as $key => $par){
            $output .= "<div class = ".$par->name.">";
            // Se muestra el padre del término como título y no se repite
            // mientras existan términos del mismo padre.
            if ($terms[$par->name] AND is_array($terms[$par->name])){
              $output .= "<h4>".$par->name."</h4>";
              foreach ($terms[$par->name] as $test) {
                $output .= l($test['name'],'taxonomy/term/'.$test['tid']) . "<br />";
              }
            }
            $output .= "</div>";  
          }
          $output .= "</div>";
        }
        else {
          // Si estamos en portada, para aquellos nodos que tengan términos
          // del vocabulario drupal, se muestra la etiqueta drupal.
          $output .= '<div class="terms">';
          $output .= "<ul><li>".l('drupal','taxonomy/term/13')."</li></ul>";
          $output .= "</div>";
        }
        // Asignación del código a la variable que será $terms en los tpl
        $vars['terms'] = $output;
      }
      else {
       // Si no hay términos del vocabulario drupal, se muestra normalmente.
    $output = '<div class="terms">';
    $output .= $vars['terms'];
    $output .= "</div>";
    //Asignación del código a la variable que será $terms en los tpl
    $vars['terms'] = $output;
      }
    }
    return $vars;
  }
  return array();
}

en la plantilla

Ya que hemos mostrado el div con clase terms en el mismo template, debemos quitarlo del tpl.
En mi caso he modificado el node-blog.tpl.php (el que se usa para el tipo de contenido blog), quitándole ese div, de esto:
<div class="terms"><?php print $terms ?></div>

A esto:
<?php print $terms ?>

el estilo css

Luego le he dado estilo css al div que se genera con un borde fino y background.

.term-drupal {
background:#E0EFF7 none repeat scroll 0 0;
border:0.1px solid #5A97AF;
float:right;
font-size:145%;
margin:0.5em 0 0 2em;
padding:0.65em;
}

Es posible que tengáis que cambiar alguno de los parámetros de float a los div que van antes y después del bloque.

últimos detalles

Como últimos detalles he tenido que corregir algunas cosas de los css para cuadrar en mi theme y sobre todo el pathauto, ya que estoy generando las URL de mi blog basándome en la categoría de cada post, es necesario modificar el vocabulario principal para que sea el prioritario (weight o peso a -1) y así se generaban las URL como hasta ahora.

otra alternativa

Otra alternativa que no he llegado a usar sería generar un bloque con la información que quisieramos mostrar (vocabularios o no) y generar una región que se situé antes del contenido (algunos themes tienen una llamada content-top) y darle formato con css (float y dimensiones) para mostrarla al lado del contenido.

Y esto ha sido todo. Espero que a alguien le haya resultado útil y si tenéis dudas o sugerencias de mejora, usad los comentarios, ¡que para eso están!