How to programatically disable regions on a drupal 7 page? - drupal

I am working on a module where i have a page that must have no regions or extra content. A kind of "please wait" page.
How do i diable all extra content (regions menus...etc) ? i think Panels has this ability but i can't find the snippet it uses.
On another hand is it possible for a module to specify a special custom page ? like the maintenance-page for example ?

The page.tpl.php method is not flexible. It is based on a presentation logic. You should use hook_page_alter() for a business logic solution. For example:
function yourmodulename_page_alter(&$page) {
if (current_path() == 'node/add/yourcontenttype') {
unset($page['sidebar_first']);
}
}
Also look at very powefull Context module.

You can create a an extra page.tpl.php specifically for the page where you want to hide the regions. The naming principle is similar to the one for nodes.
Let's say you have a page with the url example.com/content/contact. A template named page--content--contact.tpl.php would serve that page and any page that starts with that url, i.e. the page example.com/content/contact/staff would also use that template (I think).
Check the classes of the body element for clues to what you can name your template, most themes will print that. In my example above, the body element would include the class page-content-contact.

Only thing i can think of is writing checks in your page.tpl.php file to see if you on that "page" your talking about and not printing out the regions/menus, or use a different template. http://drupal.org/node/223440

If you want to do this before the blocks are rendered:
/**
* Implements hook_block_list_alter()
*
* Hides the right sidebar on some pages.
*/
function THEME_NAME_block_list_alter(&$blocks) {
// This condition could be more interesting.
if (current_path() !== 'node/add/yourcontenttype') {
return;
}
// Go through all blocks, and hide those in the 'sidebar_second' region.
foreach ($blocks as $i => $block) {
if ('sidebar_second' === $block->region) {
// Hide this block.
unset($blocks[$i]);
}
}
}
Note: Interestingly, this hook seems to work no matter if you have it in your theme or in a module.
(Please correct me if I'm wrong)

Related

Extend templates with dataextensions/modules content - SilverStripe 3.4

I could add extra functionality to a dataobject if I extend it with a dataextension. For example I've got an Item which gets extended from a module with stock keeping functionality. Let's say the Item also gets's extended form a few other modules.
After the extension with the stock keeping functionality, I'd like to display the availability of the item in the frontend, for example with a green/red dot. How can I get this dot's markup inside my template for the detail page(ItemPage.ss) and the include (Item.ss) for the overview page of items without overwriting the whole template. Just adding this one part, like the way I extend a function on my base class?
That could be a way to add extra markup to the original template.
Inside dataobject or global dataobject extension
public function ExtraTemplateHTML($position) {
$html = null;
foreach($this->owner->extend('updateExtraTemplateHTML') as $positionBlocks) {
if(isset($positionBlocks[$position])) {
foreach($positionBlocks[$position] as $htmlBlock) {
$html .= $htmlBlock->getValue();
}
}
}
return $html;
}
Inside the specific dataobject extension
public function updateExtraTemplateHTML($htmlBlocks) {
$viewer = new SSViewer(__CLASS__);
$html = $viewer->process($this->owner);
$htmlBlocks['bottom'][] = $html;
$topHtml = HTMLText::create();
$topHtml->setValue(123);
$htmlBlocks['top'][] = $topHtml;
return $htmlBlocks;
}
Original Template
$ExtraTemplateHTML(top)
...
...
$ExtraTemplateHTML(bottom)
Extension Template
Than just write a new template for your extension with the content you would like to add.
You cannot partially change a template, you can only substitute the template with another. So, keeping this in mind you should keep modular architecture with many logical includes.
Another possible way to extend existing content is using DOM and javascript. But you should think about side effects. For example if you add extra textual content then it won't be visible by crawlers and will effect your SEO. But for decorative enhancements, like adding extra coloured dot, this approach will work.

Drupal: force regions to always render?

I'd like to always render all regions. Even if they don't contain any blocks.
I render my regions like this (in page.tpl.php):
<?php print render($page['region_name']); ?>
Here's the code I'm using, but this has no effect.
function theme_name_page_alter(&$page) {
$regions = system_region_list($GLOBALS['theme'], REGIONS_ALL);
foreach ($regions as $region => $name) {
if(empty($page[$region])) {
$page[$region] = array();
}
}
}
You can make sure Drupal renders every region with the following code (in a custom module):
function hook_page_alter(&$page) {
foreach($page as $region => $blocks) {
if(is_array($blocks) && in_array($region, array('region_1', 'region_2', 'region_3'))) {
if(count($blocks)==1) {
$page[$region]['phantom_content']['#markup'] = ' ';
}
}
}
}
You will need to replace region_1, region_2, region_3 with the names of your regions that you want to make sure are always rendered.
To explain the code a little, if the count of the blocks array is 1 then it means it is empty as it will always contain the #sorted attribute.
It's not just that you don't have any blocks assigned to that region, but almost certainly because the render array is empty. Keep in mind what the render function does-- it calls drupal_render on any/all elements & children in the render array, which converts them to an html string for output. If there are no renderable elements, it doesn't return any html.
The correct (programmatic) way of rendering these regions would be to define a render array for each region, setting the #markup element to whatever html you want Drupal to output there. This would have to be done in your custom module.
If you need to do this from the gui only, I don't see any way other than defining a phantom block. In which case you should probably re-consider what it is you're trying to accomplish.
I think the answer lies in the region.tpl.php file and associated template_preprocess_region() function.
The template file checks that there is a valid variable called $content available, which is loaded up from the preprocess function. If that $content array is empty, the condition will fail and no markup will be rendered (which will happen if the region contains no blocks).
Try adding a copy of region.tpl.php to your theme, removing the if ($content): condition, and then flushing Drupal's cache.

Hide menu link for particular referrer in Drupal 7

I'm looking for a way to hide specific menu items for anonymous users under certain conditions. In particular, I serve a site for affiliates on several subdomains, and for certain subdomains (affiliates) I would like to hide the link to my 'about us' page which appears in a couple of menus.
I'm not overly bother about completely denying access to the 'about us' node, but appreciate that this might be one avenue to explore.
So far I've looked at:
* hook_menu_alter but this is only called when the menu tree is rebuilt and also I can't see how I would remove items only for a particular anonymous session.
* template_preprocess_menu_link : possible, but how to I tell the item not to render. I could add a class to the menu item that hides it, not particularly nice but it would work.
* hook_node_access : can't see how I would prevent access for only this session.
Any thoughts or pointers welcome.
[Edit]
To follow up on this, I have a solution working, but I'm not at all proud of it, there must be a nicer way. I'm using the 'hidden' class to add a css 'display:none' attribute to the list item.
function sil_affiliate_preprocess_menu_link(&$variables) {
$affiliate = get_affiliate_from_session();
if ($affiliate && !$affiliate->show_aboutus) {
$real_path = drupal_lookup_path('source','customerservice/aboutus');
if ($variables['element']['#original_link']['link_path'] == $real_path) {
$variables['element']['#attributes']['class'][] = 'hidden';
}
}
}
:wq
Familymangreg.
You can use the following code sample in your custom module. it implements hook_node_access (not tested)
function [YOUR_MODULE]_node_access($node, $op, $account)
{
if($account->uid == 0 && $op == "view" && $node->nid == 15)
{
return NODE_ACCESS_DENY;
}
}
Hope this works... Muhammad.

theme_links for aliased pages

For the sake of simplicity, let's say I just want to add the 'active' class to all links within the main menu.
The code below works for non-aliased pages. However, when I run a node that has an alias, the active class does not get applied.
I did verify the code was being triggered.
Any thoughts on how to add a class to the main menu links when viewing a node that has a url alias?
function mytheme_links__system_main_menu(array $variables) {
foreach ($variables['links'] as $key => $link) {
$variables[$key]['attributes']['class'][] = 'active';
}
return theme_links($variables);
}
If you using main menu links you would be better off using the context module instead of writing the code yourself. It will save time and headache of testing and allow you and your client to edit the the active links through a user interface instead of hard-coding the classes.
Check it out:
http://drupal.org/project/context

How to hide Edit | View tabs?

Can I hide the
Edit | View
tabs on top of each node ?
I've searched for this option in theme settings (both global and standard theme but I couldn't find it).
I still want to be able my customer to edit / administer content, so I cannot just remove the permission for it.
thanks
here is a very easy solution for you. (Drupal 7)
Open your page.tpl.php in your current template and search for the $tabs variable.
Remove the render code if you want to hide it completely.
If you want to display it only to administrators use this code
<?php if ($tabs and $is_admin): ?>
<div class="tabs">
<?php print render($tabs); ?>
</div>
The above code checks if the user is administrator. If it is it will render the tabs. If not it wont render them.
This really is a presentational thing, not a functionality thing, so it should be done at the theme level.
The problem with overriding theme_menu_local_tasks() is that you override/take a hatchet to the entire local task display, when you really just want to get in there with a scalpel to remove two specific local tasks. So, you need to get a little more specific.
theme_menu_local_tasks() gets the current page's local tasks and passes them to menu_local_tasks(). Here, two theme functions are used:
theme_menu_item_link(), which gets the link markup for the task
theme_menu_local_task(), which gets the <li> element for the task.
So, you can get rid of the View and Edit local tasks in a really robust way by overriding theme_menu_item_link() and theme_menu_local_task() to include your check for them:
function mytheme_menu_item_link($link) {
// Local tasks for view and edit nodes shouldn't be displayed.
if ($link['type'] & MENU_LOCAL_TASK && ($link['path'] === 'node/%/edit' || $link['path'] === 'node/%/view')) {
return '';
}
else {
if (empty($link['localized_options'])) {
$link['localized_options'] = array();
}
return l($link['title'], $link['href'], $link['localized_options']);
}
}
function mytheme_menu_local_task($link, $active = FALSE) {
// Don't return a <li> element if $link is empty
if ($link === '') {
return '';
}
else {
return '<li '. ($active ? 'class="active" ' : '') .'>'. $link ."</li>\n";
}
}
This way, you're relying on the menu router path, not modifying the menu router item, and achieving the result you want with minimal changes to core functionality or theming.
On the module side, you could do something that decouples the Edit's menu entry from the local tasks for the node:
function custom_menu_alter(&$items) {
$items['node/%node/edit']['type'] = MENU_CALLBACK;
}
The edit path is still there, but now it is not associated with the View tab. This includes the edit page itself--no View tab there.
there is a module for that: tab tamer allows to hide or disable tabs and rename them as well.
I use the following in template.php by theme (which is perhaps a little hacky, I feel I should be considering unsetting $tabs instead):
function THEME_NAME_menu_local_tasks() {
return '';
}
Or you could ommit:
if ($tabs) echo $tabs;
from your page.tpl.php...
View and Edit are functional features. They have a reason for being there.
The best way to "remove" them, is to "remove" that functionality alltogether. After all: why remove the interface of a piece of functionality, but not the functionality itself?
Besides, simply not printing the tabs, does not remove the url endpoints. In other words: if you don't print the edit tab, people can still access the edit page.
Again: best is to remove that functionality: The fact that you don't want the edit tab, sounds as if you don't want the edit functionality for certain users.
If so, then just remove that permission for that role. That is all. The tabs will be gone.
If, however, you simply wish to display these tabs differently, Drupal is your friends. As you may have noticed, they are called local tasks and not tabs. That is because the theme decides how to render them: The theme is the thing that decides to show them as tabs.
Simply override the theme_menu_local_tasks() to create your own HTML for the "local-tasks". And in your page-tpl, simply move the $tabs variable around to a place, where you want them.
But again: Don't try to change the behavior of the app, by removing interface-elements. That is not the right thing to do: you should change the behavior, in order to change the behavior :)
For all the people stumbling upon this question while looking for a D7 solution: As stated on https://drupal.stackexchange.com/a/77964/15055 it's hook_menu_local_tasks_alter()
/**
* Implements hook_menu_local_tasks_alter() to unset unwanted tabs
*/
function MYMODULE_menu_local_tasks_alter(&$data) {
foreach ($data['tabs'][0]['output'] as $key => $value) {
if ($value['#link']['path'] == 'node/%/view') {
unset($data['tabs'][0]['output'][$key]);
}
}
}
This is not the answer to the question of what the author asked. But somehow it might be useful for others user who facing the similar problem with me. Please let me know if this is not suitable to put in here.
I get the answer from #grayside and modified a bit to hide the view | edit tab from node based on the content type I want.
function MYMODULE_menu_alter(&$items) {
$items['node/%node/view']['access callback'] = 'MYMODULE_disable_node_view';
$items['node/%node/view']['access arguments'] = array(1);
}
function MYMODULE_disable_node_view($node){
if($node->type == 'product'){
return false;
}
}
product is the machine name of my content type, I don't want anywant to access it including root user.
The simplest solution to hide the tabs is to add this class in your theme css
.tabs{ display:none;}
Thanks for the last answer. But be aware of this detail: if you try it as-is it cannot work: literals should be just rounded with " or ', not both of them altogether. So it should be:
/**
* Implements hook_menu_local_tasks_alter() to unset unwanted tabs
*/
function MYMODULE_menu_local_tasks_alter(&$data) {
foreach ($data['tabs'][0]['output'] as $key => $value) {
if ($value['#link']['path'] == "node/%/view") {
unset($data['tabs'][0]['output'][$key]);
}
}
}
Once taken care of it, it works :)
D8 solution: If you want to hide all "local" tabs on certain pages, remember that "Tabs" is listed in the block library: find it in the "Content" region and exclude by content type, page URL or user role.

Resources