I have a Drupal 6.14 site with Views module. I have a view and on the primary links I put a link to the view.
There is a way to hide the link in the primary menu only if the view is empty?
You could probably do this either via a theme or module implementation of preprocess_page (THEMENAME_preprocess_page(&$vars) or MODULENAME_preprocess_page(&$vars)), but mac above is correct in that views are not known to be empty or not until they are run, so there will be a performance hit.
Within the function, you should have access to the structured primary links array, so you can run the view:
$view = views_get_view('view_name');
// Swap out 'default' for a different display as needed. Also, $args are arguments, and can be left out if not applicable.
$output = $view->preview('default', $args);
if (empty($view->result)) {
// The view has no results, alter the primary links here to remove the link in question.
}
I am ready to be contradicted any moment as I never implemented anything like that, however I am under the impression that since views are essentially queries against the DB, you can't actually know if a view is empty until you actually invoke it.
Consider that - given you are speaking about primary links (shown on nearly every page of your site) this might be a serious performance hit, depending on the complexity of the view and on its "cacheability".
You should also consider whether the content of that view can be changed by other users browsing the site at the same time that "our" user: should the view become populated after "our" user has loaded the page, "our" user won't ever know.
As on how to achieve what you want, please see the accepted answer.
HTH!
I override views_embed_view() to only provide output if there is content, and then call my override from the theme layer:
function mymodule_embed_view($name, $display_id = 'default') {
// handle any add'l args (this hook supports optional params)
$args = func_get_args();
array_shift($args);
if (count($args)) {
array_shift($args);
}
$view = views_get_view($name);
$output = $view->preview($display,$args);
if ($view->result) {
return $output;
}
}
Then in the template file:
<?php
$view = mymodule_embed_view('view_name');
if (strlen($view) > 0) {
print $view;
}
?>
Related
Using Drupal 6.x I have created two content types: Person and Event. Event has a custom field called Attendees (of type: Node Reference; unlimited number of values to person). When viewing a specific person how does one show all their events?
I have created a view (Personal Events) and added a block display. I enabled the block to show for content type Person. How should the view be defined? Or is there a better way?
Modules installed: CCK; Node Relationships; Views
I think one of these modules might be of help to you:
Reverse Node Reference
NodeReferrer
I have an answer to my own question. However, there maybe better answers... I can only hope.
Created content block (Personal Events)
Added this code to the body of the block. This code passes the node id argument to a view
<?php
if ( arg(0) == 'node' && is_numeric(arg(1)) && ! arg(2) ) {
$node = node_load(arg(1));
$args = array($node->nid );
$view = views_get_view('PersonalEvents');
print $view->preview('default', $args);
}
?>
Added this code to the Pages of the block [by selecting: Show if the following PHP code returns TRUE (PHP-mode, experts only)]... this drives the block to only appear person content.
<?php
//Read URL
$path=$_GET['q'];
//If URL is node page
if ( strpos($path,'node')===0){
//Parse URL to get nid
$links=explode("/",$_GET['q']);
$nid=$links[1];
//Load node
$node=node_load($nid);
//Display block only if node is of certain content type
if($node->type=='person'){
return TRUE;
}
}
return FALSE;
?>
Then created view with:
Style: Table
Relationship Content: Attendees (field_attendees); requires this relationship (checked); and Delta set to ALL.
Argument: Node: Nid; Relationship: Attendees; Hide view / Page not found (404) [selected]
Fields... simply selected Node Title and Date (for now)
Filter: Node Type = Event
Anyone have a better way?
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.
The person managing a site I'm working on wants to be able to decide what blocks go where. There is already a nice interface for this in Drupal (selecting the region from a drop down) but I'd like to hide certain blocks from this user. These are blocks he should not be able to move around.
Afaik this is not possible via the Permissions. Is there a module that allows fine grained control of what blocks can be managed by whom? I'd rather not write a custom interface ...
Thanks,
Stef
Well, you can create a simple custom module like this (replace my_module with your custom module's name, obviously):
function my_module_perm()
{
return array('view special blocks');
}
function my_module_form_alter(&$form, &$form_state, $form_id) {
if ($form_id == 'block_admin_display_form') {
if(!user_access('view special blocks')) {
$special_blocks = array( ); // Specially hidden blocks go here
foreach($special_blocks as $block) {
unset($form[$block]);
}
}
}
}
And then:
Add the blocks you want to hide into the $special_blocks array (it's basically the id of the block's div minus block_ )
Create a new account, and possibly a new role for this guy
Permission-wise, the new user's role should have access administration pages and administer blocks on, but shouldn't have view special blocks
Tested on Drupal 6.6, should work on other 6.x versions (and maybe 5.x with a few modifications)
Take those blocks out of regions and embed them into your template manually using module_invoke().
$block = module_invoke('module_name', 'block', 'view', 'block name or ID');
print '<h2>' . $block['subject'] . '</h2>';
print $block['content'];
Maybe give Blockqueue a try? I've never used it, but it appears to cover your use case.
I am currently using drupal 6 for a site I'm working on. I have a MYTHEME_preprocess_page() function that adds a few variables to the page.tpl.php template from the taxonomy and from a cck field. It was working correctly for a bit, and then the $vars['node'] is empty, but only for 2 content types. The 'node' variable is available to the preprocess_page function in other content types.
I thought it was a problem with using the following code, but when I remove all of this, the 'node' variable is still empty.
function mytheme_preprocess_node(&$vars, $hook) {
$function = 'mytheme_preprocess_node'.'_'. $vars['node']->type;
if (function_exists($function)) {
$function(&$vars);
}
}
Does anyone know of any gotchas or bugs that might be removing the 'node' variable? I can't seem to figure out where I'm going wrong. I'm at a loss.
Here is my complete mytheme_preprocess_page() function.
function mytheme_preprocess_page(&$vars, $hook) {
if ($hook == 'node' || $hook == 'page') {
if (is_object($vars['node'])) {
// grab the header image if it exists to make it avaialble to the content header
$vars['header_image'] = _mytheme_get_header_image($vars);
// get the taxonomy term to put in the content header
if (count($vars['node']->taxonomy) > 0) {
$vars['tax_term'] = "<div class=\"terms\">" . _mytheme_get_first_taxonomy_term($vars['node']->taxonomy) . "</div>";
}
// add the teacher's credentials to the content header
if ($vars['node']->field_credentials[0]['view'] != '') {
$vars['teacher_credentials'] = '<span class="teacher-creds">' . $vars['node']->field_credentials[0]['view'] . '</span>';
}
}
}
}
After going through and disabling modules one-by-one, I determined that the problem is related to the module, node_breadcrumb. A similar issue was filed here: http://drupal.org/node/616100#comment-2199374
In the 3rd comment, you'll see a link to another issue with a resolution
For others that run into this, I had the same issue as a result of using the jQuery UI module. Disabling and re-enabling fixed it, and I could not track down the specific issue, but it appeared to be related to $static variables in some path check functions.
To others that stumble their way into here, I suggest you pull some of the more obvious modules right out of the module folder on your dev setup, see if things change, and then put them back in there until you figure it out.
Another option is to search for instances of _preprocess_page(, $variables['node'] and $vars['node'] to see if some contributed code is unwittingly unsetting a node when it shouldn't be.
I have a View with an exposed form . I am trying to a few things on it. Ideally I would like to have a dropdown that fires the form with no button. If that is not possible then I would like to have the button text something different than apply.
I hacked it for now and change views_form in views.module but that does not seem like the right way to do it. I only have one exposed form right now, but what if I add more?
Please see http://www.wiredvillage.ca/News for my example.
I am poking around drupal.org and seeing others with the same problem but no solutions so far. Not sure where the best place to get Drupal help is.
Here is the change I made so far:
function views_exposed_form(&$form_state) {
// Make sure that we validate because this form might be submitted
// multiple times per page.
$form_state['must_validate'] = TRUE;
$view = &$form_state['view'];
$display = &$form_state['display'];
$form_state['input'] = $view->get_exposed_input();
// Let form plugins know this is for exposed widgets.
$form_state['exposed'] = TRUE;
$form['#info'] = array();
if (!variable_get('clean_url', FALSE)) {
$form['q'] = array(
'#type' => 'hidden',
'#value' => $view->get_url(),
);
}
// Go through each filter and let it generate its info.
foreach ($view->filter as $id => $filter) {
$view->filter[$id]->exposed_form($form, $form_state);
if ($info = $view->filter[$id]->exposed_info()) {
$form['#info']['filter-' . $id] = $info;
}
}
// I CHANGED The VALUE OF THIS SUBMIT BUTTON TO GO
$form['submit'] = array(
'#name' => '', // prevent from showing up in $_GET.
'#type' => 'submit',
'#value' => t('go'),
);
$form['#action'] = url($view->get_url());
$form['#theme'] = views_theme_functions('views_exposed_form', $view, $display);
$form['#id'] = views_css_safe('views_exposed_form-' . check_plain($view->name) . '-' . check_plain($display->id));
// $form['#attributes']['class'] = array('views-exposed-form');
// If using AJAX, we need the form plugin.
if ($view->use_ajax) {
drupal_add_js('misc/jquery.form.js');
}
views_add_js('dependent');
return $form;
}
Or, you could use a preprocess function to alter the form even before it is build. I wanted to change the text on the button, so I did this:
function MYTHEME_preprocess_views_exposed_form(&$vars, $hook) {
// only alter the jobs search exposed filter form
if ($vars['form']['#id'] == 'views-exposed-form-jobs-search-page-1') {
// Change the text on the submit button
$vars['form']['submit']['#value'] = t('Search');
// Rebuild the rendered version (submit button, rest remains unchanged)
unset($vars['form']['submit']['#printed']);
$vars['button'] = drupal_render($vars['form']['submit']);
}
}
If you want the drop-down to fire, I'd use JavaScript instead of hacking the module as Eaton suggests.
Basically, you can modify the text with hook_form_alter as Eaton suggests, then use in the same hook_form_alter, add a call to drupal_add_js with your custom JS which hides the button and submits the form on the onChange handler of the select drop-down. You want that submit button there for those 10% of users for whom the JS fails.
Both of the above are fine but I found out that altering the form might not always lead to desirable results, mainly because exposed filters are themed using a specifc theme template. The proper way of changing the theme would be to override the views-exposed-form.tpl file in your theme's folder. Bear in mind that this will apply to all exposed filter forms, to theme a specific one, you will need to use a different name for that filename, like:
views-exposed-form--TITLE--DISPLAY.tpl.php
views-exposed-form--TITLE.tpl.php
and some others, you can check the Theme: Information section of your views for template naming conventions.
This module provides an auto-submit among other things http://drupal.org/project/views_hacks
This module is great to improving exposed filters http://drupal.org/project/better_exposed_filters
You should be able to use hook_form_alter() (http://api.drupal.org/api/function/hook_form_alter) to change the form as it's built, modifying the fields in question when that particular view is being displayed. You can nuke the submit button, add a #theme function that calls the drupal_add_js() function, and so on.
As long as the GET params come in the way views expect them, everything will work fine -- it was designed that way to allow bookmarking of pages with exposed filter settings, etc. The important part is to make sure you're doing the form mangling in your own module's hook_form_alter() function, so that it won't make other views driven stuff choke.