Monday, November 16, 2009
Control book outline form and menu for specified Drupal node types
Problem:
The problem using Drupal book module and book pages as wiki is, the book page module adds book outline form part and the book outline menu as node/x/outline to all node types. All the node types do not need to be part of a book/wiki page. So this is the awkward part. I had to develop an application that had a wiki as a part with blogs and events as other services. So I faced this problem.The Search:
Then I searched for the solution to show book outline form part and the book outline module in only specified Drupal nodes/content types. At the d.o (I hear this in all screencasts and podcasts - its Drupal.org ;) ) site I found this node: http://drupal.org/node/251798 - and a code snippet by mooffie. But the code was very basic and not configurable or flexible.A Simple Move:
I decided to use the code as it was a solution to my problem but also thought to make a configurable module out of it. So the module is called nobookoutline now, I have not put it in d.o as I'm not confident of getting a CVS account :). Here is the download link for the module.The Solution:
The module provides a user interface to select which node/content types you want to show the book outline form and /outline menu option to. Below is the screen-shot of the page you can see in Admin>> Content>> Book Outline Settings after you download and enable the module and login as site admin. you can access the page by going to admin/content/nobookoutline.After you select the appropriate node types and click save the book outline form and the menu node/x/outline will only appear on the desired node types. Like below:
Below is a book node that has outline, other nodes will not have the outline menu unless they are selected in the configuration page.
The book outline menu appears only for selected node types.
Edited Code:
The code has been edited to accommodate the new configuration page and here is a snippet below:<?php
/**
* Implementation of hook_form_alter
* @param $form
* @param $form_state
* @param $form_id
* @return NULL
*/
function nobookoutline_form_alter(&$form, $form_state, $form_id) {
if (isset($form['#node']) && $form_id == $form['#node']->type .'_node_form') {
$node = $form['#node'];
// If it's not a book node, remove the Book Outline box:
// now get settings as set.
$nodetypes = variable_get('form_nobookoutline_nodetypes', array('book'));
if(!in_array($node->type, $nodetypes)) {
$form['book']['#access'] = FALSE;
}
}
}
/**
* implementation of hook_menu_alter
* @param $callbacks
* @return unknown_type
*/
function nobookoutline_menu_alter(&$callbacks) {
// We install our own access callback to check if node is book type
$callbacks['node/%node/outline']['access callback'] = '_nobookoutline_restrict_outline_tab';
}
// Additional access control for the 'Outline' tab: don't show for non 'book' nodes...
function _nobookoutline_restrict_outline_tab($node) {
$nodetypes = variable_get('form_nobookoutline_nodetypes', array('book'));
if(!in_array($node->type, $nodetypes)) {
return FALSE;
}
// Delegate to the original access callback:
return _book_outline_access($node);
}
?>
What the code does is, it just restricts access to the form part and the menu link.
Conclusion
The module can be made better with permissions but is functional enough for now. Hope it solves your problem.Using Drupal as a wiki will not be a big deal if this minor issue is resolved. Happy Drupalling.
Monday, November 9, 2009
Show Drupal blocks only on specific pages with PHP code
Drupal blocks are the basic building elements of any Drupal page. Blocks are placed in block regions and they serve different purposes from showing a list of elements even to show a picture or a video.
Menus of the Drupal system are also blocks of special kind that show links to other drupal nodes/pages/url or external links. (I assume that you know about drupal blocks and how they can be shown or hidden on basic given conditions and also you have some knowledge of php.)
Having a look at a block's configuration page (Site Building >> Blocks >> List) and clicking configure aside one of the block descriptions there are various ways to control the visibility of a particular Drupal block.Some are let users control what they see, to show only to block to only specific roles.
The Need
In page specific visibility the first two options are quite clear, you want to show a particular block in some url and its sub URL like setting to option 2 : "Show on only the listed pages." and typing the following on pages:
- blog - will show the block on siteURL/blog page only
- blog/* - will show the block on siteURL/blog/any url - pages
But what if I want to show a block in one node type (or content type), then the need to choose the third option "Show if the following PHP code returns TRUE (PHP-mode, experts only)." arises. It does not need expert knowledge.
Scenario 1: For node types
After selecting the third option on "Page specific visibility settings", the logic is quite simple if TRUE is returned the block is shown if FALSE is returned the block is hidded from display. Lets say I want to see a the block only on story content type, then I can do it by pasting the code below on the PHP code option in page specific visibility settings.
<?php
// Only show if $return is true
$return = FALSE;
// Match current node type with story
if ( (arg(0) == 'node') && is_numeric(arg(1)) ) {
$nid = arg(1);
$node = node_load($nid);
$type = $node->type;
if($type == "story") {
$return = TRUE;
}
}
return $return;
?>
In action:
You can further enhance it with multiple node types with use of the in_array() php function to show multiple node types. Or tweak it to fit your custom needs.
Scenario 2: For OG (Group) nodes
I had yet another problem I needed to show some specific blocks like group calendar, group blogs only to OG - Group nodes and only to group members. So I digged into the OG module and found two very good functions, they are:
- og_get_group_context(): Used for things like setting current theme and breadcrumbs. - Check og module for more information or see it here.
- og_is_group_member(): Check a user's membership in a group. More here.
So using these two functions I can show a block only when a group node is loaded and only to the group's members with the code below:
<?php
$return = FALSE;
if ($groupnode = og_get_group_context()) {
if(og_is_group_member($groupnode->nid)) {
$return = TRUE;
}
}
return $return;
?>
The above code could have been better :). Above code should also be put in the "Page specific visibility" of the block configuration settings page.
Better Use and Possibility
A better use of the above code I assume will be to make a module and call a function. The function will determine to show the blog or not. It will give a central control of the code else if one thing is changed like in scenario one if node type has to be blog from story it should be edited in all the blog config pages which is a very bad solution. So calling a function form lets say for now a custom_show_block module with function: custom_show_block_normal() will do the trick. Below is a screenshot in assumption that custom_show_block module has been created and custom_show_block_normal() function in custom_show_block module has code of scenario 1:
If the module will have setting to choose the node types and other things it would be great ;).
Conclusion
Block visibility with PHP is very flexible and customizable like other parts of Drupal. With block visibility for specific pages with PHP the need to show a block for specified condition will be easier. Happy coding.






