I'm using Panels to overwrite node template (node/%node). I would like the system to use specific variant when a node is loaded. E.g. node 123 should use variant A and node 223 should use variant B. There isn't an option for me to determine that under Selection rules, I'm wondering if I should use PHP Code, and if I do, how should I go about writing the code?
I'm aware of the option of using Panels Node, but by using it, there is no easy way to edit the node thus rendering it a less than desirable choice.
In this case the easiest thing is probably to throw in some PHP code. It would be prettier to make an extension to the Panels selection rules, but this might be a bit overkill in this case.
Anyways something like
return arg(1) == 123;
should do it.
Your problem is probably Drupal/Panel cache. I just tested it, and it works fine.
You'll need to do something like this...
$nid = 11;
if (arg(0) == 'node' && arg(1) == $nid && !arg(2)) {
return true;
}
return false;
Be careful only testing arg(1) as in the previous answer, that will also match users (user/123) as well as any page view that accepts a numeric argument (articles/123).
Related
I am asked to develop an application where a member can select 1 plan, a combination of plans, all plans, or none.
plan1, plan2, plan3, .... plan12
I ran the truth table to find out how many possibilities there are, and it turned out to be 4096. (Ridiculous!)
My plan was to write an if statement for each possibility like this:
if (plan1.Checked == true && plan2.Checked == false && ... && plan12.Checked == false){
// insert into into table test VALUES('Plan1')
}
and so on! Obviously, there must be a better and easier way than this. Any suggestions would help. Thank you all.
If you used a CheckBoxList or similar component this would be one approach.
CheckBoxList checkBoxList = ....; // Just an example here
// You would add the different project names into the CheckBoxList
String message = "";
for (int i = 0; i < checkBoxList.Items.Count; i++) // Look at every project name
{
if (checkBoxList.Items[i].Selected) // See if it's selected
{
message += checkBoxList.Items[i].Text; // Add the name to the message
}
}
Put message in DB; // <-- Store the message into your database here
Since you're only interested in selected items you wouldn't have to deal with non-selected items at all.
Note: There is probably a better/more efficient way of creating strings than this and you might be able to use lambda expressions. This is just showing a simple approach.
Andrew_CS answer is suitable and I prefer it, but here is another way:
Handle the checked event in the code behind of all checkboxes (use one event, but allow all checkboxes to be handled by it), and depending on the sender, then you can load the information you want.
It may be that you use a Select statement to load the relevant information for each checkbox during the checkbox checked event (might be a little easier to understand than a for loop!)
I would like to limit the use of some url's. Let's say node/add and node/7 (just random examples). I'm thinking the best way to do this is to use the user_access function.
But as we are used to it, the Drupal documentation doesn't help much. When I just use the function, I get the message the function is already in use. So my best guess is to use this existing function with my own arguments in my custom function in my custom module.
But in this way I need to catch the page before loading it. Or I'm I missing something here?
EDIT:
I've set this
global $user;
$items['node/add/%']['access callback'] = array('_mymodule_node_access');
$items['node/add/%']['access arguments'] = array(0,2, $user);
But for some reason, Drupal isn't picking up the % card for all types. It's just working for one type (script). Other terms like page or fiche aren't getting picked up... % is a Drupal wildcard right?
EDIT:
I just found out there are already some paths in the database. How can I overwrite them? What I need is one selector which can select all four content types (fiche, page, script and news-item).
The way to define a particular access function for a path is to set the access callback for the path's menu item in hook_menu(). This is slightly different for existing paths, in that you need to implement hook_menu_alter() to edit the existing access callback for that path:
function mymodule_menu_alter(&$items) {
$items['node/add']['access callback'] = 'mymodule_node_add_access_callback';
}
function mymodule_node_add_access_callback() {
// return TRUE to allow access, FALSE to deny
}
This gets a bit more fun when we're talking about node pages as their menu items is defined using a wildcard node/%. This means that using hook_menu_alter() you can only change the access callback for all nodes.
Fortunately Drupal has a hook_node_access hook to come to the rescue:
function mymodule_node_access($node, $op, $account) {
$restricted_nids = array(7, 10, 12);
if (in_array($node->nid, $restricted_nids) && $op == 'view') {
if ($some_condition_is_true) {
return NODE_ACCESS_ALLOW;
}
return NODE_ACCESS_DENY;
}
return NODE_ACCESS_IGNORE;
}
Hope that helps
EDIT
If that all seems like a bit much hassle you might get some joy installing the Path Access module, I think it has the functionality you're after.
ANOTHER EDIT
I think the reason overriding the wildcard isn't working in this case is because the node module explicitly defines a path for each node type, e.g. node/add/page, node/add/article, etc. Because Drupal will take an exact match (node/add/page) over a wildcard match (node/add/%) you're actually overriding the wrong menu item.
Try specifying the path explicitly in your hook_menu_alter() function (note that the access callback should be a string and not an array as you currently have):
$items['node/add/page']['access callback'] = '_mymodule_node_access';
$items['node/add/page']['access arguments'] = array(0,2, $user);
It's also worth noting that the $user object you're passing will always be the user object of the logged in user who cleared Drupal's caches (since menu items are rebuilt when the cache is rebuilt). If you're looking to pass the current logged in user (i.e. the one logged in at the time the page is accessed) that's a different thing altogether...I'd advise asking another question on it as it can be a tricky bugger and you want to get as much input as possible from people on here.
I'm trying to give my users the functionality to change what the background image used on a page is.
The list of background images will be a small number that won't really change.
I thought I could add a few Taxonomy terms...one for each background type...then apply a class to the body tag when the page is viewed.
Does this sound feasible and if so how would I go about doing it?
Thanks
Sam
EDIT: revised answer after clarification of my misunderstanding of the question
If the background image is to be defined per (node) page, your approach via a taxonomy vocabulary sounds like the right way to go. To make the terms available for CSS, the easiest way would be to just output/use them as classes in the node.tpl.php file(s), where you have direct access to the $node variable. But in that case, they are somewhat buried in the middle of the resulting markup, which makes it a bit difficult to use them properly.
In order to add them to the $body_classes variable in the page.tpl.php, you'd have to either manipulate the zen_preprocess_page() function to add them as well, or (better approach) add them to your own modules/themes preprocess_page() function, using the zen function as an example:
function yourModuleOrTheme_preprocess_page(&$vars) {
// Add classes for body element based on node taxonomy
// Is this a node page?
if ('node' == arg(0) && is_numeric(arg(1))) {
// Yes, extract wanted taxonomy term(s) and add as additional class(es)
$node = node_load(arg(1));
$background_vid = yourFuntionToGetTheBackgroundVocabularyId(); // Could be hardcoded, but better to define as variable
$terms = $node['taxonomy'][$background_vid];
foreach ($terms as $tid => $term) {
// NOTE: The following assumes that the term names can be used directly as classes.
// You might want to safeguard this against e.g. spaces or other invalid characters first.
// Check the zen_id_safe() function for an example (or just use that, if zen is always available)
$vars['body_classes'] .= ' ' . $term;
}
}
}
NOTE: Untested code, might contain typos and other oversights.
(Original answer before edit - based on a misunderstanding of the OPs intent, left her in case other misunderstand it as well :)
The basic idea sounds feasible, but I'd suggest a minor variation:
Since you want the setting to be adjustable per user, you would have to jump through some hoops to allow users to 'tag' themselves with a taxonomy term. I think it would be far easier to just enable the (core, but optional) profile module and configure a 'background' field there (with type 'list selection'). The field will show up on the user page (or a separate tab on that page, if you give it a category), and the user selection will be available from code later on quite easily, e.g. to derive a class for the page template:
global $user;
// NOTE: The following call would be the explicit way,
// but usually the profile fields get added to the $user object
// automatically on user_load(), so you might not need to call it at all,
// extracting the values directly from the $user object instead
$profile = profile_load_profile($user);
$background = $user->profile_background
Here's my custom module; it basically fetches a file from a particular URL, saves it on temporary folder and then i want it to modify a cck field of type 'file' (field name being : field_video_thumb) :
function mymodule_nodeapi(&$node, $op) {
switch ($op) {
case "update":
$node->field_video_thumb[0] =
field_file_save_file ($filename, array(),
$files_path, FILE_EXISTS_REPLACE);
// node_save($node);
break;
}
}
The problem i have here is that when i ucomment the 'node_save($node)' it works (but calls recursively of course) and removing it does not do anything.
I must be missing something really obvious but can't figure it out.
I have answered a similar question a while ago. There are some additional steps involved, but the most important difference to your attempt is to use the 'presave' operation of hook_nodeapi() instead of 'update', as update happens after the node has been updated.
(The code in the answer was taken from a utility class, so you would need to adjust it a bit to work from within a function.)
How can one hook exit in a custom module be called in every page request of a drupal website?
Here is the hook exit code in a custom module:
<?php
function cec_monitoring_exit() {
if ((arg(0) == 'node') && is_numeric(arg(1)) && arg(2) == '') {
// database inserts here
}
}
?>
Is it because of the if condition or someting else? Because some of the custom modules are calling the hook 'cec_monitoring_exit()' but some other custom modules don't.
Thanks in advance.
Cheers,
Mark
I'm not sure what you mean by it is not called in some of the custom modules either, so just speculating here that you might mean custom pages provided by other modules:
As Jeremy and Googletorp stated already, your if block
if ((arg(0) == 'node') && is_numeric(arg(1)) && arg(2) == '') {
// database inserts here
}
will only evaluate to true if the user is requesting a full node page (e.g. 'node/42'). It will not match any other page like a term view (e.g. 'taxonomy/term/36') or the default frontpage ('node') or a view page provided by the views module (might/have/any/path), etc..
So your database inserts would only take place for node pages, and nothing else.
If you want to log every page request, you can just remove the if block and do your database insertions directly.
Edit after clarification in comments (cec_monitoring_exit() does not get invoked for some pages created by other modules):
I can only see two possible reasons for this.
The first reason would be an error occurring right after the page output, but before the invocation of your hook_exit() implementation (check your server logs for php errors on requests for the failing pages). If you take a look at 'index.php' (top level folder of your Drupal instance):
require_once './includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
$return = menu_execute_active_handler();
// Menu status constants are integers; page content is a string.
if (is_int($return)) {
switch ($return) {
case MENU_NOT_FOUND:
drupal_not_found();
break;
case MENU_ACCESS_DENIED:
drupal_access_denied();
break;
case MENU_SITE_OFFLINE:
drupal_site_offline();
break;
}
}
elseif (isset($return)) {
// Print any value (including an empty string) except NULL or undefined:
print theme('page', $return);
}
drupal_page_footer();
you can see that the page output is generated by printing the result of theme('page', $return). The invocation of hook_exit() happens right after that in drupal_page_footer().
So you should check (preferably via debugger, but you could also use print statements) if drupal_page_footer() gets executed on the pages in question at all. If it gets called, the error might occur in a hook_exit() implementation of another module that gets called before yours, so you'd need to check those.
The second reason would be if one of the modules would circumvent the standard Drupal execution flow by calling theme('page', ...) itself and stopped the execution afterwards. In this case, drupal_page_footer() would not be called, because the execution would have stopped long before during the call to menu_execute_active_handler(). Note that no established Drupal Module would do this, so it is pretty unlikely.
Besides these options, I have no further idea on what could cause this.
Hooks are called whenever their condition is met. This is done with the use of module_invoke_all(). This means that hooks that are called on every page request, will be invoked in every page request. In your example above, your hook wont do anything in some cases, but it will still be called since Drupal wont know when it actually will do something.
This waste of resource will be limited when pages are cached, since you only will need to run the hooks when page cached page is created. Another example is whenever a node is loaded with node_load, this will result in a lot of hooks being fired, and is thus quite expensive. Thus you usually want to avoid using this whenever possible, when you want to access something on a lot of nodes like their title.
#marknt15 what i think your failing to realize here is its all based on name so that hook being the hook_exit() in your case AKA _exit() is called when it is placed with a prefix of the calling modules name eg cec_monitoring_exit() will only work in the cec_monitoring module but in you other custom module named say marknt15_loves_drupal then it would meed to use hook_exit() like marknt15_loves_drupal_exit()
drupal then calls it and all other hooks with ...
call_user_func_array('modulename'_'hookname') or something very similar