Problem saving imagefield using hooks in Drupal 6 - drupal

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.)

Related

How to make one dropdown exposed filter (constrained list e.g. options) to search across in two fields (identical lists) in drupal 7 views

Help! I've done a lot of research and looking for answers, both here and elsewhere but the solution to my particular problem has so far eluded me.
I'm building a search in drupal views to return users who meet certain criteria. I have the search currently doing most of what I need (proximity searching, combined name searching etc.), but I am looking for one last thing:
Each user has a list of activities they can do that they are certified to do, and a separate list of activities they can do, that they are NOT certified to do.
Both lists are constrained lists (e.g. a list of options) and both lists are identical.
e.g. List A [drive, ski, skate, fly], List B [drive, ski, skate, fly].
Normally searchers are only interested in searching for users in List A. My current search does this fine.
What I would like is an "Include Non-Certified" checkbox that when checked, uses the exposed dropdown filter for List A, and returns users who have the selected item in List A OR List B.
I have found lots of methods for searching multiple fields from one exposed filter, but they all apply to string / text entry searches, NOT to a dropdown list of options type filter.
I've looked at things like: "Global: Combine fields filter (exposed)", or the "Better Exposed Filters Drupal Module" and "Views filters populate Drupal module" but I can't see a way to get them to do what I want.
Any help would be much appreciated. I understand it seems to be a fairly unusual requirement. I also hope the above explanation is clear.
I do not know of a module that will do this, but, you could create your own module and implement hook_views_query_alter to alter the query before it is executed.
In the hope that it helps someone else with a similar problem, I'll sketch out what I had to do to solve this using the advice of 2pha above:
Make a custom module (MODULENAME), install and enable it.
Inside the module directory make a MODULENAME.form.inc file, use this to add a checkbox to the form. This checkbox will be used to toggle if we are searching only List A, or both List A & List B.
-- MODULENAME.form.inc:
<?php
function MODULENAME_form_alter(&$form, &$form_state, $form_id) {
}
function MODULENAME_form_views_exposed_form_alter(&$form, &$form_state, $form_id) {
// Add a checkbox to search form.
$form['togglecheckbox'] = array(
'#type' => 'checkbox',
'#title' => t("Include List B"),
'#required' => FALSE,
);
}
--
Make a MODULENAME.views.inc file. This will check the state of the checkbox and change the search query to include List B as needed.
Because my search is more than just List A (or List A or List B), I add a bunch of extra filters to the new query also.
-- MODULENAME.views.inc:
<?php
function MODULENAME_views_query_alter(&$view, &$query) {
// Uncomment the below line to get the query object via devel module debug
// dpm($query);
// If the checkbox is checked, then we want to use the exposed primary key also as the secondary key
if ($view->name == 'VIEWNAME' && ($view->exposed_raw_input['togglecheckbox'] == '1')) {
// Set variable to primary key
$primary_key = ($view->exposed_raw_input['field_LIST_A']);
// Add table to query, since it doesn't seem to automatically be done to exposed filters unless their value has been changed from the default (ALL for selection lists etc.)
$query->add_table('field_data_field_LIST_B', 'users');
$view->query->set_group_operator('OR'); // Show results that match group 1 (normal) or group 2 (added)
// Add secondary filter to search query
$query->add_where(2,'field_data_field_LIST_B.field_LIST_B_value',$primary_key,'=');
// Fill in other filters, e.g. Must be valid member, must be ok for directory
// User must be valid
$query->add_where(2,'users.status',0,'<>');
// The below key name is mine, you'll need to change to yours or delete this line.
$query->add_where(2,'field_data_field_list_in_directory.field_list_in_directory_value',1,'=');
}
I struggled a bit with the naming conventions, used a lot of dpm(); debug calls (via devel module) to constantly check on variables.
I also call dpm($query); which lists the entire query structure, so you can explore it and help figure out what's going wrong and what things are called.
Finally you need a MODULENAME.module to initialise both the above.
-- MODULENAME.module:
<?php
function MODULENAME_hook_info_alter(&$hooks) {
$hooks['form_alter']['group'] = 'form';
}
function MODULENAME_views_api() {
return array('api' => 2.0);
}
--
Good luck!

How to properly use user_access($string, $account) in Drupal?

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.

Why can't I move a field into a fieldset in a Drupal form - fails to pick up current value

I have a node form in Drupal 7, in order to simplify it for the user I want to break it up into sections using the vertical tabs feature.
Using hook_form_FORMID_alter() I can move the fields without difficulty. When the node is saved, it writes the values correctly, and they appear in the node view.
But when I re-edit the node any value for a moved field is not set so I effectively lose the data. I've tried various options including changing the array_parents value in form_state['fields'][field][langcode].
(I wondered whether it would be better to move the fields during pre_render instead.)
Any ideas?
Field API fields by default are placed into a container field type. If you want to convert them to a fieldset in the vertical tabs, you can do the following:
$form['field_tags']['#type'] = 'fieldset';
$form['field_tags']['#title'] = 'Tags';
$form['field_tags']['#group'] = 'additional_settings';
A better solution would be to use the new Field Group module so you can make these modifications through the UI, rather than in code.
Sometimes it works better to move field items around in the #after_build step of the form creation process.
in hook_form_alter, you set your after build function like so:
function mymodule_form_alter(&$form, &$form_state, $form_id)
{
$form['#after_build'][] = 'mymodule_myform_after_build';
}
Then you define your after_build function like so:
function mymodule_myform_after_build($form)
{
//do stuff to the form array
return $form;
}
I think you can even define after_build on individual elements.
Anyway, it's a good way to alter the form after all the modules have done their thing.

Changing background image of a Drupal page based on user's selection...?

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

Drupal: How can one hook exit in a custom module be called in every page request?

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

Resources