Drupal : how to sort and display nodes grouping by first letter in view

13,308

Solution 1

To do what you want to do using Views, and not some other contributed module, like Glossary, you'll have to define and theme your own view.

First, you'll need to create a new node View. I'm going to call it myglossary, but it doesn't matter. Make sure that one of your fields is the node title, and that it's sorted by node title, ascending. In other words, alphabetical order. I'm assuming you'll be using the unformatted row style (it's default), but you can probably do something similar with the other row styles.

Then, you'll have to get into your theme. From the views/theme folder, copy the views-view-unformatted.tpl.php template into the folder of the theme you're using. Rename it to views-view-unformatted--myglossary.tpl.php so it will only be used for this view. Then, open up your theme's template.php file, and add a preprocess function:

//Change mytheme to your theme name
function mytheme_preprocess_views_view_unformatted__myglossary(&$vars) {
  //If you have the devel module installed,
  //this is a great way to see all the available variables
  //dpm($vars);

  $results = $vars['view']->result;
  $rows = $vars['rows'];

  //Sort rows into letter sets
  $letters = array();
  $i = 0;
  foreach ($results as $result) {
    $first_letter = strtolower(substr($result->node_title, 0, 1));
    if (is_array($letters[$first_letter])) {
      array_push($letters[$first_letter], $rows[$i]);
    }
    else {
      $letters[$first_letter] = array($rows[$i]);
    }
    $i++;
  }

  //Generate glossary navigation
  $nav = '';
  foreach($letters as $letter => $rows) {
    $num = count($rows);
    $cap_letter = strtoupper($letter);
    $nav .= <<<NAV
<a href="#$letter" class="letter_link">
  $cap_letter
</a>
($num)
NAV;
  }

  //Add to variables
  $vars['nav'] = $nav;
  $vars['letters'] = $letters;
}

Then, you'll have to change the template file you copied over earlier to add in the navigation, and to output the rows in a glossary style:

<?php if (!empty($title)): ?>
  <h3><?php print $title; ?></h3>
<?php endif; ?>

<?php if (!empty($nav)): ?>
  <div id="glossary_nav">
    <?php print $nav; ?>
  </div>
<?php endif; ?>

<?php foreach ($letters as $letter=>$rows): ?>
  <a name="<?php print $letter ?>"></a>
  <h4 class="letter">
    <?php print strtoupper($letter); ?>
  </h4>
  <?php foreach ($rows as $id=>$row): ?>
   <div class="<?php print $classes[$id]; ?>">
    <?php print $row; ?>
   </div>
  <?php endforeach;?>
<?php endforeach; ?>

You might need to regenerate the theme registry to have your changes show up on your site.

Solution 2

You don't really need to go down the code path to achieve this. You can see some of this described here: http://drupal.org/node/641342

Basically, add the node title to the view twice. The first is your normal field with links, etc. The second one is for the grouping.

The second field you mark to exclude from display, remove the label, and trim the field to a maximum length of 1 (uncheck the word boundary, ellipsis, and html options).

Then, under the "row style" options you'll find the "group by" setting, and you just select the second node title field.

You may need to apply additional theming if you want to have it look a certain way or possibly adding anchors for each letter, but otherwise that should work for version 6 of Drupal with views 2 module

Also, I should point out the group by module http://drupal.org/project/views_groupby which can offer some additional functionality but which isn't really needed for the original question.

Solution 3

Take a look at the Views module, which provides a view called "Glossary". That sorts content alphabetically, and creates a letter index of sorts. Also take a look at http://drupal.org/node/441024 though it's possible she used the Glossary module. There's also a module called Dictionary (demo).

Solution 4

The module Views grouping Limit may get you where want to go.

Solution 5

If you use the Views module, have you tried using a preprocess method in the template? You wouldn't be returning the data from your datasource in that fashion but you could sort it by any arbitrary method you wanted to once it was returned, it would look something like this:

function templatename_preprocess_views_view__All_Images(&$vars)
{
    global $base_url;
$images = array();
//drupal_add_js('$("a.colorbox").colorbox();','inline');
foreach($vars['view']->result as $img)
{
    $nid = $img->nid;
    $node = node_load($nid);
    $images[$nid]['orig_img_url'] = $base_url . '/' . file_create_path($node->images['_original']);
    $images[$nid]['thumb_img_url'] = $base_url . '/' . file_create_path($node->images['thumbnail']);
}
$vars['images'] = $images;

}

That way you could sort by first letter and make changes to the array and it would get sent out to your view in the fashion you desire. This is an example I made for image paths but you could use PHP's variety of sorting methods to get the sorting you require.

Share:
13,308

Related videos on Youtube

Disco
Author by

Disco

Come and ask, i don't bite :)

Updated on June 04, 2022

Comments

  • Disco
    Disco almost 2 years

    I have a huge list of companies (nodetype : company, only field is title) that I want to display in a nice way groupping them by first letter like a dictionnary like this :

    A
    Abc company
    Alot of work company
    
    B
    Beautiful company
    Best company
    

    Trying to find a way to do it in an elegent way; no module seems to exist for that. Any idea ?

  • Disco
    Disco over 13 years
    Thx almost what I wanted; followed your link and came to that one nanwich.info/glossary that does EXACTLY what I want. But i'm stuck in the views args; i want to show all the letters but I can only specify 1 character
  • Disco
    Disco over 13 years
    Nope; i don't want to limit actually; i want to group BY the first letter of node title.
  • Collin White
    Collin White over 13 years
    use a print_r($vars) to see what variables you will be working with. You can then alter these variables before they are used in your view.
  • shanabus
    shanabus over 13 years
    Can't you leave the views arg blank and then it will show all?
  • messedup
    messedup about 13 years
    This approach might work, but you don't need to do this. You can achieve the same affect without any custom code.

Related