Adjustments to PHP snippet for book navigation
almawr - January 24, 2006 - 14:46
Hello and thanks to Coreyp_1 for submitting the great PHP snippet that enables one to make a book navigation block appear on all pages (See: http://drupal.org/node/44648)!
What I would like is to have the lowest level in the navigation not only show a link but also the plain body text (node->body).
Who can help me?

Shouldn't be too difficult.
By "lowest level" do you mean (1.) the last item in the tree, or, (2.) the deepest level navigated to.
Perhaps you could give us an illustration?
Thanks for the encouragement!
I am only testing local at this stage.... the book navigation structure is as follows:
Section A (level 1)
Section B (level 1)
The end of the tree is always an "element", but this element is sometimes in level 4 and in other cases in level 5 (when there is no component - I might need to add a category term to all elements to work around that problem?). So the last item in the tree needs to be a link AND show the plain body text.
Also the "activities" (level 2) are in many cases commented on, and I would like to add a link to the first comment.
Thanks!
My first attempt without the PHP snippet
My first attempt was as follows. It works fine but watchdog gets crowded with SQL syntax errors. Quess I am no PHP expert.......
<?php
if (arg(0) == 'node' && arg(1)) {
$node_load_array = array('nid' => arg(1));
$node = node_load($node_load_array);
$_GET['nid'] = $node->nid; }
$sql = "SELECT DISTINCT node.title, node.nid FROM node, book WHERE book.parent = 269 AND book.nid = node.nid ORDER BY node.title";
$result = db_query($sql);
while ($anode = db_fetch_object($result))
{
echo "</ul><b>".l($anode->title, "node/$anode->nid")."</b><ul>";
foreach ($anode as $section)
{
$sql2 = "SELECT DISTINCT node.title, node.nid FROM node, book WHERE book.parent = $section AND book.nid = node.nid ORDER BY node.title";
$result2 = db_query($sql2);
while ($anode = db_fetch_object($result2))
{
echo "<li>".l($anode->title, "node/$anode->nid")."</li>";
foreach ($anode as $act)
{
$sql4 = "SELECT DISTINCT node.title, node.nid, comments.subject, comments.cid FROM node, book, comments WHERE comments.nid = $act AND comments.nid = node.nid ORDER BY node.title";
$result4 = db_query($sql4);
if ($anode = db_fetch_object($result4))
{
echo " ".l("[COMMENTARIES]", "node/$anode->nid#comment-$anode->cid")."";
}
{
$sql3 = "SELECT DISTINCT node.title, node.nid FROM node, book WHERE book.parent = $act AND book.nid = node.nid AND node.title LIKE '%component%' ORDER BY node.title";
$result3 = db_query($sql3);
while ($anode = db_fetch_object($result3))
{
echo "<ul><li>".l($anode->title, "node/$anode->nid")."</li></ul>";
}
}
}
}
}
}
?>
sorry for the delay, work has kept me busy!
well, it may not be the prettiest piece of code, but I believe that this will do it for you:
<?php
>
global $_book_levels_deep;
global $_book_children;
if (!isset($_book_children)) {
$_book_children = array();
}
$book_top_page = 269;
$emulate_book_block = true;
$_book_levels_deep = 5;
if (!function_exists('book_struct_recurse')){
function book_struct_recurse($nid, $levels_deep, $children, $current_lineage = array(), $emulate_book_block = true, $first = true) {
$struct = '';
global $_book_levels_deep;
if ($children[$nid] && ($levels_deep > 0 || ($emulate_book_block && in_array($nid, $current_lineage)))) {
$struct = '<ul>';
foreach ($children[$nid] as $key => $node) {
$id = ($first ? ' id="book_menu_first"' : '');
$first = false;
if (($_book_levels_deep - $levels_deep + 1) == 2 && comment_num_all($node->nid) > 0) {
$comment_link = ' ' . l('[COMMENTARIES]', "node/$node->nid#comment");
}
else {
$comment_link = '';
}
if ($tree = book_struct_recurse($node->nid, $levels_deep - 1, $children, $current_lineage, $emulate_book_block, false)) {
$struct .= '<li class="expanded"' . $id . '>';
$struct .= l($node->title, 'node/'. $node->nid);
$struct .= $comment_link;
$struct .= '<ul>'. $tree .'</ul>';
$struct .= '</li>';
}
else {
if ($children[$node->nid]){
$struct .= '<li class="collapsed"' . $id . '>'. l($node->title, 'node/'. $node->nid);
$struct .= $comment_link;
$struct .= '<br>';
$struct .= strip_tags($node->body);
$struct .= '</li>';
}
else {
$struct .= '<li class="leaf"' . $id . '>'. l($node->title, 'node/'. $node->nid);
$struct .= $comment_link;
$struct .= '<br>';
$struct .= strip_tags($node->body);
$struct .= '</li>';
}
}
}
$struct .= '</ul>';
return $struct;
}
}
}
$current_lineage = array();
if ($_book_children == array()){
// only do this query if this is the first time it is called on the page
$result = db_query(db_rewrite_sql('SELECT n.nid, n.title, n.body, b.parent, b.weight FROM {node} n INNER JOIN {book} b ON n.nid = b.nid WHERE n.status = 1 ORDER BY b.weight, n.title'));
while ($node = db_fetch_object($result)) {
if (!$_book_children[$node->parent]) {
$_book_children[$node->parent] = array();
}
array_push($_book_children[$node->parent], $node);
}
}
if (arg(0) == 'node' && is_numeric(arg(1)) && arg(1) == $node->nid) {
$_temp = book_location($node);
foreach ($_temp as $key => $val){
$current_lineage[] = $val->nid;
}
$current_lineage[] = arg(1);
}
$struct .= book_struct_recurse($book_top_page, $_book_levels_deep, $_book_children, $current_lineage, $emulate_book_block);
echo $struct;
?>
I had to guess at a few things, so let me know if it needs to be fine tuned.
Error in PHP snippet
I noticed a typo in the PHP snippet (See http://drupal.org/node/44648):
<?phpelse {
if ($children[$node->nid]){
$struct .= '<li class="collapsed"'. l($node->title, 'node/'. $node->nid) .'</li>';
}
?>
'>' after "collapsed" is missing, causing the lowest level in the tree not to be hyperlinked. I think it should read:
<?phpelse {
if ($children[$node->nid]){
$struct .= '<li class="collapsed">'. l($node->title, 'node/'. $node->nid) .'</li>';
}
?>
thanks.
thanks for flagging that...I have ammended the book page
Dub
Getting weird tree using the book navigation block snippet
Hi,
I am new to drupal, and I tried to use the book navigation block snippet found at http://drupal.org/node/44648.
I am getting duplicates for specific nodes... e.g.:
In this case only two tree branches have the problem. I checked that the SQL query gets the right results (around line 38) but the $children array created in the while loop (around line 40) have duplicate entries for two of the book chapters...
The children array had the duplicate entries identical (node id, parent) except the weight. The weight was right in the first occurrence but 0 on the duplicates
I have tried to troubleshoot without luck.
Any ideas?
Thanks,
vp
Probably...
This is probably because of the new (OK, not that new, but it didn't exist in the same way when this snippet was originally written) revisioning system. Use this updated SQL statement, as pointed out later in the comments.
It *SHOULD* work.
SELECT n.nid, n.title, b.parent, b.weight FROM {node} n INNER JOIN {book} b ON n.nid = b.nid AND n.vid = b.vid ORDER BY b.weight, n.title- Corey
That was it!!!
Thanks so much
vp