Alert: Drupal Noob
I'm trying to do something that should be simple, but having extraordinary difficulty doing it. I am new to Drupal but have built sites in Joomla and CMSimple, as well as having extensive prior HTML experience. My PHP and SQL knowledge is basic at best.

Brief:
How do you display an entire book to users in Drupal? I've tried the "Whole Book in a Block" php snippet (that just shows the table of contents and not the pages) and I've tried doing it via Views as per http://drupal.org/node/289646, but both are ineffective.

(The explanation on the latter page is causing a couple of pages to appear, but never more than that.)

Detail of Desire:
I have a book with over a dozen separate book pages in an outline form going as deep as four levels. I like having the book navigation on the left, and thus would like to keep the pages as pages, but I also want the capacity to show the entire book at once, like a big flat HTML file. I also do not want to have the bottom-of-the-page book navigation (e.g. the back - up - next) showing on the view of the whole book. Preferably the headers can be attractive (e.g. like a proper outline-based webpage).

Yes, I could simply copy the assorted pages into one page displayed separately, but then I am creating two separate locations at which I have to edit the same text should I ever make changes, which defeats the entire purpose of a CMS.

History:
Copying from an old flat HTML page that was very large but in well-organized outline form (with a bookmark/anchor list at the top for ease of navigation and color-coded H1-H4 headers), I have created a book.

I have figured out how to use CCK to create a special content type for another use and then make Views show all of that content type, and have the capacity to show a block as a page, but I have no current insight on how to use any of that kind of knowledge to create a simple whole book view. I am astonished that it isn't just a checkbox or something, so I'm assuming I am doing something wrong.

Please let me know if you have any further questions or need any further detail.

Comments

matt_harrold’s picture

I don't have a solution for you, but when you use "Printer Friendly" versions of a book, the entire book tree is displayed (current book page and children).

Perhaps you could look at the code used to produce these large document trees, and adapt it to your needs.

Either way .. it is certainly possible. Sorry I can't be any more help.

TheGuardian’s picture

Sorry, yes, I'm aware of the Printer Friendly version, but that strips the page to as close to black-and-white as it can. I still want the theme showing like the user is still on the site and not staring at a text file.

Thanks for the quick response, though!

TheGuardian’s picture

I think I have a little something with views, but:

1. It shows poorly, what with the prev/up/next sort of stuff between every page, not to mention failed heirarchical organizing.

2. Surely there's a basic core way to implement this.

TheGuardian’s picture

My continued attempts with Views are still proving fruitless. Even weighted book pages and/or title ordering are producing off-the-wall sorting.

I would much rather this be something in the core, but I've given up searching in the core of Drupal for now, pending response.

TheGuardian’s picture

I'm just making it a page since there was no way to get rid of the prev/up/next stuff, and while having the ability to view it a single book page was very good, the old-style flat view will have to suffice for now.

The funny thing is, CMSimple had code for this sort of thing. And that's CMSimple! (sigh)

matt_harrold’s picture

Have a look at the code in book.module ... particularly the book_export_traverse() function.

This is the code used by Printer Friendly ... it CAN be done ... I just can't tell you exactly how (not experienced with this issue).

btilma’s picture

Using views (Drupal 6):

This method creates a view that takes a top-level book node id(nid) as an argument, and displays the whole book in flat, one-page html. Create the view as a node view. On the edit screen, create two relationships. The order here is important.

  • Book: Parent
  • Book: Top level book

Next, create an argument:

  • Node: Nid

and choose the relationship "Book" (the label of Book: Top level book). Now you'll need two sort criteria, to make sure the pages are sorted properly. In this order (both ascending):

  • Book: Hierarchy
  • Book: Weight

Now you'll have to choose how you want it displayed. Under "Row Style", you can choose node, and for format choose "print" for printer-friendly. This will take the printer-friendly output and put it into the output section on your site. The printer-friendly page shows a book as one long page, so this is a simple way of accomplishing this. If you'd like more control over your output, choose "fields" under output. Then, in the fields section, you can specify the "Node: Title" and "Node: Body" fields. You can then use the override function to customize the way that the text is output.

Don't forget to change the "Items to display" option to allow for all of your book pages to be displayed, and add a page output type and give it a url alias. You can then call the view like so:

http://<your domain>/<url alias>/<nid>

Todd Young’s picture

That was good stuff, thanks for the post. I'm surprised there's not a more readily-available way to print a book, it somewhat dampens the value of having a book type, but using this method worked pretty well.

Todd Young’s picture

I'm trying to do the same with Forums, and it's working for the most part, but I'd like it to also print the container names as "headers" - do you have an idea as to how I can do that?

I'd like hierarchical output with "category - category - forum - node" output, but right now it will skip any forum that has no nodes, and it skips containers entirely.

A.  Category One (container)

A01.  Forum X (forum)

Blah Blah Blah (node)

Yada Yada (node)

Any pointers appreciated!

ak’s picture

... but I can't get it to work! I left out the sort criteria to simplify it but get following errror:

user warning: Unknown column 'node_book.bid' in 'on clause' query: SELECT node.nid AS nid, node.title AS node_title, node.language AS node_language FROM node node LEFT JOIN book book ON node.nid = book.nid LEFT JOIN menu_links book_menu_links ON book.mlid = book_menu_links.mlid LEFT JOIN book book_parent ON book_menu_links.plid = book_parent.mlid LEFT JOIN node node_book_parent ON book_parent.nid = node_book_parent.nid LEFT JOIN node node_book ON book.bid = node_book.bid WHERE node_book.nid = 3 in .../modules/views/includes/view.inc on line 769.

Is there a detail missing in your description? Can somebody paste a working exported view?

ak’s picture

As soon as I add the relationship "Book: Top level book" the only results I get are errors? this just doesn't work, please can anybody paste a working recipe?

chawl’s picture

Gosh! This saved my life. Thanks gazillion times.

sime’s picture

The only thing you didn't clarify AFAICT is which relationships (if any) the sort fields use. At any rate this didn't quite work for me using various combinations but I will have another crack at this I think.

If anyone really has got this working they should export their view and share.

ak’s picture

Hi there, here's what finally worked for me. It needs the node id of the parent node as argument. Hope this helps.

$view = new view;
$view->name = 'book_outline';
$view->description = 'Zeigt alle Inhalte eines Buches an.';
$view->tag = 'custom';
$view->view_php = '';
$view->base_table = 'node';
$view->is_cacheable = FALSE;
$view->api_version = 2;
$view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
$handler = $view->new_display('default', 'Standards', 'default');
$handler->override_option('relationships', array(
  'nid' => array(
    'label' => 'Book parent',
    'required' => 0,
    'id' => 'nid',
    'table' => 'book_parent',
    'field' => 'nid',
    'relationship' => 'none',
  ),
));
$handler->override_option('fields', array(
  'title' => array(
    'label' => '',
    'alter' => array(
      'alter_text' => 0,
      'text' => '',
      'make_link' => 0,
      'path' => '',
      'link_class' => '',
      'alt' => '',
      'prefix' => '',
      'suffix' => '',
      'target' => '',
      'help' => '',
      'trim' => 0,
      'max_length' => '',
      'word_boundary' => 1,
      'ellipsis' => 1,
      'strip_tags' => 0,
      'html' => 0,
    ),
    'empty' => '',
    'hide_empty' => 0,
    'empty_zero' => 0,
    'link_to_node' => 1,
    'exclude' => 0,
    'id' => 'title',
    'table' => 'node',
    'field' => 'title',
    'relationship' => 'none',
  ),
));
$handler->override_option('arguments', array(
  'nid' => array(
    'default_action' => 'ignore',
    'style_plugin' => 'default_summary',
    'style_options' => array(),
    'wildcard' => 'all',
    'wildcard_substitution' => 'Alle',
    'title' => '',
    'breadcrumb' => '',
    'default_argument_type' => 'node',
    'default_argument' => '',
    'validate_type' => 'none',
    'validate_fail' => 'not found',
    'break_phrase' => 0,
    'not' => 0,
    'id' => 'nid',
    'table' => 'node',
    'field' => 'nid',
    'validate_user_argument_type' => 'uid',
    'validate_user_roles' => array(
      '2' => 0,
      '5' => 0,
      '3' => 0,
      '4' => 0,
    ),
    'relationship' => 'nid',
    'default_options_div_prefix' => '',
    'default_argument_user' => 0,
    'default_argument_fixed' => '',
    'default_argument_php' => '',
    'validate_argument_node_type' => array(
      'webform' => 0,
      'blog' => 0,
      'feed' => 0,
      'feed_item' => 0,
      'flashnode' => 0,
      'nodequeuenode' => 0,
      'sitebadge' => 0,
      'book' => 0,
      'file' => 0,
      'image' => 0,
      'page' => 0,
      'project' => 0,
      'quote' => 0,
      'story' => 0,
      'task' => 0,
      'viewpage' => 0,
    ),
    'validate_argument_node_access' => 1,
    'validate_argument_nid_type' => 'nid',
    'validate_argument_vocabulary' => array(
      '3' => 0,
      '2' => 0,
      '4' => 0,
      '1' => 0,
    ),
    'validate_argument_type' => 'tid',
    'validate_argument_transform' => 0,
    'validate_user_restrict_roles' => 0,
    'validate_argument_php' => '',
    'override' => array(
      'button' => 'Override',
    ),
  ),
));
$handler->override_option('access', array(
  'type' => 'perm',
  'perm' => 'access content',
));
$handler->override_option('cache', array(
  'type' => 'none',
));
$handler->override_option('items_per_page', 0);
$handler->override_option('style_plugin', 'list');
$handler->override_option('style_options', array(
  'grouping' => '',
  'type' => 'ul',
));
$handler = $view->new_display('page', 'Page', 'page_1');
$handler->override_option('path', 'bookoutline/%');
$handler->override_option('menu', array(
  'type' => 'none',
  'title' => '',
  'description' => '',
  'weight' => 0,
  'name' => 'navigation',
));
$handler->override_option('tab_options', array(
  'type' => 'none',
  'title' => '',
  'description' => '',
  'weight' => 0,
  'name' => 'navigation',
));

sime’s picture

Thanks for sharing!

bwoods’s picture

This seems to work for me as well. I started my own view initially, but it was even easier just to import this one. Thanks!

operations’s picture

Thanks for the usefull steps and information ! I tried it and it worked perfectly..

Michsk’s picture

For those who want to embed the view in the book parent node, set the filter to book: depth greater than 1. This will filter out the first result.

I tried to offset option, but that doesn't seem to be working with this.

Eric B.’s picture

Thanks! This method worked perfectly in D7 and Views 3!

gebhart_m’s picture

This worked for me...except the sorting. Somehow it's still displaying a section further down before it's displaying the children of a section above. But this got me a lot further than I was. Thank you.

Shadlington’s picture

I have managed to get this to work and I wanted to share for anyone else that wanted to do this.
Its a little convoluted as it requires you to install a module that is intended for a completely separate purpose.

The first thing you need to do is install DraggableViews. Enable it and the sub-module 'DraggableViews Book handler'.
This book handler is included so that you can create draggable views of books, which is pretty great all by itself, but the interesting thing here is that part of this module is a new views argument: 'Book: All sub nodes of this book page'.

You can now create your own view using this new argument or you can just clone the one provided by draggableviews book handler and change its style to unformatted nodes. It'll then show all nodes that are children of the node you pass to the argument.

The only thing that I'm not completely happy with for this is that the book nav gets printed with the nodes still. I got around this by displaying the nodes in teaser format, but I had to set teaser length to unlimited for this to meet my needs - something that is hardly ideal. If anyone can come up with a clean way of stripping book nav out of node output in views I would be extremely grateful.

ak’s picture

You should be able to locate book-navigation.tpl.php somewhere in the book module folder. That's the source of the outputted book navigation html so copy it to your theme, delete the code in it and clear your caches. Now the default book navigation shouldn't show up anymore.

Shadlington’s picture

Hmmm. That sounds good - thanks!
Is there any way to selectively remove the navigation from a particular view?
I don't want to remove the book nav on the actual book pages themselves (the node/nid pages) itself, but on a related view.
The nav is fine on a page with one node, its just annoying in a page made up of several nodes one after another, each with their own nav.

thanvn’s picture

Flatbook, worked for me, exactly what I wanted, certain Book pages showing all nodes (children / leafs)
http://drupal.org/project/flat_book
Thanks!

gausarts’s picture

This should go to your custom module block:

     $content = '';
      $node = menu_get_object();
      if(isset($node->book) && !empty($node->book['bid'])) {
	    $pid = $node->book['bid'];
        $tree = menu_tree_all_data(book_menu_name($pid));
		$data = array_shift($tree);
		$content = drupal_render(menu_tree_output($data['below']));		
	  }

      return $content;

More discussion here:
http://drupal.org/node/44648

love, light n laughter

l-laziz’s picture

@gausarts
This worked for me, but throws this error:
"Strict warning: Only variables should be passed by reference in custom_data() (line 8 of C:\Users\sites\all\modules\custom\custom\custom.module)."?
Can you help me please?

The module code:

  1. <?php
  2. function custom_data() {
  3. $node = menu_get_object();
  4. if(isset($node->book) && !empty($node->book['bid'])) {
  5. $pid = $node->book['bid'];
  6. $tree = menu_tree_all_data(book_menu_name($pid));
  7. $data = array_shift($tree);
  8. $content = drupal_render(menu_tree_output($data['below']));
  9. }
  10. return $content;
  11. }
dimaboychev’s picture

You're probably not even getting the node_id. I hard coded the node ID and the code works. It renders the book contents (pages) nicely, all the levels with expansion capability.

sime’s picture

@Akumaru menu_get_object() will only work on urls like /node/123

jcmartinez’s picture

You can see the full output of the book by visiting http://your-site-url/full-book/top-book-page-nid (e.g.: http://goingdrupal.com/full-book/123).

$view = new view();
$view->name = 'full_book';
$view->description = '';
$view->tag = 'default';
$view->base_table = 'node';
$view->human_name = 'Full book';
$view->core = 7;
$view->api_version = '3.0';
$view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */

/* Display: Master */
$handler = $view->new_display('default', 'Master', 'default');
$handler->display->display_options['title'] = 'Full book';
$handler->display->display_options['use_more_always'] = FALSE;
$handler->display->display_options['access']['type'] = 'perm';
$handler->display->display_options['cache']['type'] = 'none';
$handler->display->display_options['query']['type'] = 'views_query';
$handler->display->display_options['exposed_form']['type'] = 'basic';
$handler->display->display_options['pager']['type'] = 'none';
$handler->display->display_options['style_plugin'] = 'default';
$handler->display->display_options['row_plugin'] = 'node';
$handler->display->display_options['row_options']['view_mode'] = 'print';
$handler->display->display_options['row_options']['links'] = FALSE;
/* Relationship: Book: Parent */
$handler->display->display_options['relationships']['nid']['id'] = 'nid';
$handler->display->display_options['relationships']['nid']['table'] = 'book_parent';
$handler->display->display_options['relationships']['nid']['field'] = 'nid';
/* Relationship: Book: Top level book */
$handler->display->display_options['relationships']['bid']['id'] = 'bid';
$handler->display->display_options['relationships']['bid']['table'] = 'book';
$handler->display->display_options['relationships']['bid']['field'] = 'bid';
$handler->display->display_options['relationships']['bid']['required'] = TRUE;
/* Field: Content: Title */
$handler->display->display_options['fields']['title']['id'] = 'title';
$handler->display->display_options['fields']['title']['table'] = 'node';
$handler->display->display_options['fields']['title']['field'] = 'title';
$handler->display->display_options['fields']['title']['label'] = '';
$handler->display->display_options['fields']['title']['alter']['word_boundary'] = FALSE;
$handler->display->display_options['fields']['title']['alter']['ellipsis'] = FALSE;
/* Sort criterion: Book: Hierarchy */
$handler->display->display_options['sorts']['p']['id'] = 'p';
$handler->display->display_options['sorts']['p']['table'] = 'book_menu_links';
$handler->display->display_options['sorts']['p']['field'] = 'p';
$handler->display->display_options['sorts']['p']['sort_within_level'] = 0;
/* Sort criterion: Book: Weight */
$handler->display->display_options['sorts']['weight']['id'] = 'weight';
$handler->display->display_options['sorts']['weight']['table'] = 'book_menu_links';
$handler->display->display_options['sorts']['weight']['field'] = 'weight';
/* Contextual filter: Content: Nid */
$handler->display->display_options['arguments']['nid']['id'] = 'nid';
$handler->display->display_options['arguments']['nid']['table'] = 'node';
$handler->display->display_options['arguments']['nid']['field'] = 'nid';
$handler->display->display_options['arguments']['nid']['relationship'] = 'bid';
$handler->display->display_options['arguments']['nid']['title_enable'] = TRUE;
$handler->display->display_options['arguments']['nid']['title'] = '%1';
$handler->display->display_options['arguments']['nid']['breadcrumb_enable'] = TRUE;
$handler->display->display_options['arguments']['nid']['breadcrumb'] = '%1';
$handler->display->display_options['arguments']['nid']['default_argument_type'] = 'fixed';
$handler->display->display_options['arguments']['nid']['summary']['number_of_records'] = '0';
$handler->display->display_options['arguments']['nid']['summary']['format'] = 'default_summary';
$handler->display->display_options['arguments']['nid']['summary_options']['items_per_page'] = '25';
/* Filter criterion: Content: Published */
$handler->display->display_options['filters']['status']['id'] = 'status';
$handler->display->display_options['filters']['status']['table'] = 'node';
$handler->display->display_options['filters']['status']['field'] = 'status';
$handler->display->display_options['filters']['status']['value'] = 1;
$handler->display->display_options['filters']['status']['group'] = 1;
$handler->display->display_options['filters']['status']['expose']['operator'] = FALSE;

/* Display: Page */
$handler = $view->new_display('page', 'Page', 'page');
$handler->display->display_options['path'] = 'full-book/%';
jcmartinez’s picture

After importing this view you can add the block that it creates to any book page. This block will use the node id (nid) of the current book page to show a link to the page with the full book generated using the view above.

$view = new view();
$view->name = 'full_book_link';
$view->description = 'Identifies and creates a link to a to a full book view';
$view->tag = 'default';
$view->base_table = 'node';
$view->human_name = 'Link to Full Book';
$view->core = 7;
$view->api_version = '3.0';
$view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */

/* Display: Master */
$handler = $view->new_display('default', 'Master', 'default');
$handler->display->display_options['title'] = 'Link to Full Book';
$handler->display->display_options['use_more_always'] = FALSE;
$handler->display->display_options['access']['type'] = 'perm';
$handler->display->display_options['cache']['type'] = 'none';
$handler->display->display_options['query']['type'] = 'views_query';
$handler->display->display_options['exposed_form']['type'] = 'basic';
$handler->display->display_options['pager']['type'] = 'some';
$handler->display->display_options['pager']['options']['items_per_page'] = '5';
$handler->display->display_options['style_plugin'] = 'default';
$handler->display->display_options['row_plugin'] = 'fields';
/* Relationship: Book: Top level book */
$handler->display->display_options['relationships']['bid']['id'] = 'bid';
$handler->display->display_options['relationships']['bid']['table'] = 'book';
$handler->display->display_options['relationships']['bid']['field'] = 'bid';
$handler->display->display_options['relationships']['bid']['required'] = TRUE;
/* Field: Content: Nid */
$handler->display->display_options['fields']['nid']['id'] = 'nid';
$handler->display->display_options['fields']['nid']['table'] = 'node';
$handler->display->display_options['fields']['nid']['field'] = 'nid';
$handler->display->display_options['fields']['nid']['relationship'] = 'bid';
$handler->display->display_options['fields']['nid']['label'] = '';
$handler->display->display_options['fields']['nid']['exclude'] = TRUE;
$handler->display->display_options['fields']['nid']['element_label_colon'] = FALSE;
/* Field: Content: Title */
$handler->display->display_options['fields']['title']['id'] = 'title';
$handler->display->display_options['fields']['title']['table'] = 'node';
$handler->display->display_options['fields']['title']['field'] = 'title';
$handler->display->display_options['fields']['title']['relationship'] = 'bid';
$handler->display->display_options['fields']['title']['label'] = '';
$handler->display->display_options['fields']['title']['alter']['alter_text'] = TRUE;
$handler->display->display_options['fields']['title']['alter']['text'] = 'Full book: [title]';
$handler->display->display_options['fields']['title']['alter']['make_link'] = TRUE;
$handler->display->display_options['fields']['title']['alter']['path'] = 'full-book/[nid]';
$handler->display->display_options['fields']['title']['alter']['word_boundary'] = FALSE;
$handler->display->display_options['fields']['title']['alter']['ellipsis'] = FALSE;
$handler->display->display_options['fields']['title']['element_label_colon'] = FALSE;
$handler->display->display_options['fields']['title']['link_to_node'] = FALSE;
/* Sort criterion: Content: Post date */
$handler->display->display_options['sorts']['created']['id'] = 'created';
$handler->display->display_options['sorts']['created']['table'] = 'node';
$handler->display->display_options['sorts']['created']['field'] = 'created';
$handler->display->display_options['sorts']['created']['order'] = 'DESC';
/* Contextual filter: Content: Nid */
$handler->display->display_options['arguments']['nid']['id'] = 'nid';
$handler->display->display_options['arguments']['nid']['table'] = 'node';
$handler->display->display_options['arguments']['nid']['field'] = 'nid';
$handler->display->display_options['arguments']['nid']['default_action'] = 'default';
$handler->display->display_options['arguments']['nid']['default_argument_type'] = 'node';
$handler->display->display_options['arguments']['nid']['summary']['number_of_records'] = '0';
$handler->display->display_options['arguments']['nid']['summary']['format'] = 'default_summary';
$handler->display->display_options['arguments']['nid']['summary_options']['items_per_page'] = '25';
/* Filter criterion: Content: Published */
$handler->display->display_options['filters']['status']['id'] = 'status';
$handler->display->display_options['filters']['status']['table'] = 'node';
$handler->display->display_options['filters']['status']['field'] = 'status';
$handler->display->display_options['filters']['status']['value'] = 1;
$handler->display->display_options['filters']['status']['group'] = 1;
$handler->display->display_options['filters']['status']['expose']['operator'] = FALSE;

/* Display: Block */
$handler = $view->new_display('block', 'Block', 'block');
swortis’s picture

This is a cool solution, but non-top book pages are still accessible and are now blank (example: http://your-site-url/full-book/child-book-page-nid). This can create SEO havoc. 

Is there a way to have individual child-level book pages appear normally, but the complete book shown on the top-page?

(Alternatively, one can simply create a block which appears in the main content region with a relationship (parent book node; required), and then a context filter (node ID; relationship=book parent; provide default value--type: content ID from URL)

This method gives you a flat complete book but doesn't kill individual child nodes in the book.