Display (x) full nodes followed by (y) teasers

Last modified: January 26, 2007 - 04:51

PLEASE NOTE These snippets are user submitted. Use at your own risk. For users who have setup Drupal using an alternate database to the default (MYSQL), please note that the snippets may contain some database queries specific to MYSQL.

From a list of categories and/or taxonomy terms, display (x) most recent nodes in full, followed by (y) nodes as teasers

For a community website I needed a front page that displayed the most recent story in full form, followed by a list of story with teasers and appropriate links. I wrote the following somewhat more general bit of code based on a primitive query builder.

There are several variables you can use to customize the list. Both the number of full articles and teasers can be adjusted by modifying the respective list length. The taxonomy terms and content types can be customized by providing comma-separated lists of each. Note that content types need to be passed to the database as a string, and hence should be delimited by extra single quotes.

It's possible to narrow the selection in other ways, too (e.g. by user). Just include the necessary tables in the SQL statement and make the necessary additions to the WHERE clause.

<?php
/**
* This PHP snippet displays a list of nodes in full,
* followed by another list of nodes as teasers
* (e.g. 1 full node, followed by 5 teasers)
*
* It's possible to narrow the selection by taxonomy
* term and by content type.  Other customizations
* can be added by modifying the query builder.
*
* Works with drupal 4.6.x
*
* Snippet by Philipp Reichmuth (rxmd)
* Includes code by Robert Garrigos (robertgarrigos)
* and Sean Robertson (seanr)
*/

$filter_by_taxonomy = TRUE;
$taxo_id = "1,2,5"; /* comma seperated list */

$filter_by_content = TRUE;
$content_type = "'story'"; /* comma-separated list of entries, each in extra single quotes */  

$list_length_full = 1;
$list_length_teasers = 5;

$sql = "SELECT * FROM {node},{users} INNER JOIN {term_node}";
 
/* If you need to filter on other information, include the necessary tables here */
$sql .= " ON {node}.nid = {term_node}.nid WHERE {node}.uid = {users}.uid";
 
/* and don't forget to add the primary and secondary keys to the WHERE clause */

if ($filter_by_taxonomy) {
 
$sql .= " AND {term_node}.tid IN ($taxo_id)";
};

if (
$filter_by_content) {
 
$sql .= " AND {node}.type IN ($content_type)";
};
/* Add similar statements if you need to filter on other information */

$list_length = $list_length_full + $list_length_teasers;
$sql .= " ORDER BY {node}.created DESC LIMIT $list_length";

$result = db_query($sql);
$count = 1;
while (
$anode = db_fetch_object($result)) {
  if (
$count <= $list_length_full) {
   
$output .= node_view(node_load(array('nid' => $anode->nid)), $teaser = FALSE, $page = FALSE, $links = TRUE);   
  } else {
   
$output .= node_view(node_load(array('nid' => $anode->nid)), $teaser = TRUE, $page = FALSE, $links = TRUE);
  };
 
$count++;
}
print
$output;
?>

articles showing up twice

PipSqueak - May 21, 2006 - 09:36

This snippet is extremely awesome! But I have some articles in two categories and this snippet is showing these same articles twice in the list. Can you make the snippet appear only once in the page?

Thanks.

Yeah, something's a bit off

PAAHCweb - August 27, 2006 - 18:22

Yeah, something's a bit off here. I'm filtering by a single content type, no taxonomy. Instead of showing all the available nodes of that content type, it's showing the last created node several times.

BTW, for me, it would be ideal to have (x) teasers followed by (x) titles (linked to full nodes).

D. Lynn

Articles Show Up Twice - Need a DISTINCT wrapper in the SELECT

pinemind - September 6, 2006 - 18:59

Hi,

Haven't tried this yet but I'm sure you will need a DISTINCT() wrapper around the node_id field in the '_node' table. Otherwise, because of the join table where nodes can exist under multiple taxonomies, there can be more than one row of node_id's in this join table. So without DISTINCT(), it will pull all rows where the taxonomy matches the WHERE clause for the taxonomy.

I'll take a look at that query tonight when I get back from "working for the man" and "work for myself" on this solution. Just need to list out all the fields necessasry because by defining DISTINCT(node_id), you either need to list out the remaining necessary fields or use {node}.* (might work) to get this.

$sql = "SELECT DISTINCT(nid) as nid, {node}.* FROM {node},{users} INNER JOIN {term_node}";

Try that until I get home from web slave labor camp using Coldfusion . . . shudder.

Peace,
J

DISTINCT works - Change INNER JOIN on term_node to LEFT JOIN

pinemind - September 7, 2006 - 18:25

All,

DISITINCT will help to grab only the node id's once. However, since when joining a Node to the term_node page there can be more than one term_node row per node, if the taxonomy id's are needed to create the view, then two rows will always be returned, hence 2 instances of the node id. The easiest way would be to use a query like this to just obtain the node id's necessary in the correct order. Then when cycling through, grab the taxo id's for each node (not sure if that's how Drupal works, but the db logic is correct).

Also, consider switching the INNER JOIN on the term_node table to LEFT JOIN because not all node's may have a taxonomy term associated and if you aren' t using the $taxonomy_filter, then nodes without taxo terms won't show up.

SELECT DISTINCT(n.nid), n.*, u.* FROM node n INNER JOIN users u USING(uid) LEFT JOIN term_node tn ON (n.nid = tn.nid) ORDER BY n.created DESC LIMIT 5

This will return all distinct node id's (Limit 5) with no restrictions.

Justin

How to do this in Drupal 5, 6 or 7?

Sam-Inet - July 11, 2009 - 20:52

This old page comes up first when doing a search for this. And it took a bit to find the info for later releases.

1) Drupal 5
2) Drupal 6 http://drupal.org/node/430126#comment-1460998
3) Drupal 7

Please add links for D5 and D7, as well as any other links that help with this.

Sam

 
 

Drupal is a registered trademark of Dries Buytaert.