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
Related
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!
I have developed wordpress for days,but I have found no way to these like:add_action,add_filter,user_can, I don't know what are the functions they refere to.
worse still,I don't know the parameter,today I want add a column to user list table admin panel,I fortunatelly found a tutorial, here is the code
add_filter( 'manage_users_columns', 'add_user_column');
function add_user_column( $columns){
$columns['available_stickers'] = __('Stickers Available', 'available_stickers');
return $columns;
}
add_filter('manage_users_custom_column', 'add_user_column_value', 10, 3);
function add_user_column_value( $value, $column_name, $user_id ){
if ( 'available_sticker' == $column_name)
$value = get_user_meta($user_id,"available_stickers",true);
return $value;
}
Even thought I made it, but I don't know where the parameter manage_users_columns comes or why I should use manage_users_columns but not other code? Puzzled
and also they have matched code like apply_filter etc.
some one can help me out of the maze,oops!
WordPress is beautifully designed because most of the actions it does are not executed directly, but through what are called actions and filters. This gives you, the developer, a possibility to hook onto any of these operations. Hooking means you can squeeze your own logic right in the middle of WP's logic, in a very clean way, only by declaring that you want things to be done where the corresponding hooks are used. More precisely:
Actions
So, for example, when a post is saved, WordPress does not just save the post, it does it by executing this line:
do_action( 'save_post', $post_ID, $post );
This is a way to give a name to this action (save_post). That means two things :
1) you can execute the exact same action by using the same line of code somewhere else.
2) you can add your own logic to be executed during this action. How? just by "adding" your custom functions to the action, like this :
add_action('save_post', 'name_of_the_function_you_want_to_execute_when_post_is_saved');
So 'save_post' is the name of the hook, add_action gives you the possibility to add your own function to the action for this hook and do_action actually executes the action.
Filters
Filters are similar to actions, but instead of being used when executing a command, they are used to treat a value, an object, a string or some text (when "filtering" it). Again, instead of just manipulating objects and strings in such a way that you would have no other possibility than dive into the core code to access it, WordPress cleverly does many of its "filtering" operations with a special action called apply_filters(). This gives you the possibility, like for actions, to actually add your own filters to the filters already applied. So when showing the content of a post, WP would execute :
apply_filters('the_content', $post->post_content);
The name of the hook is the_content. If you use :
add_filter('the_content', 'your_function_to_execute_to_further_filter_content');
you can have a function named your_function_to_execute_to_further_filter_content()that can take the content as a parameter and return the filtered version of it after whatever treatment you wish to apply to it. Then this treatment will get applied anywhere in WP where the hook the_content is used to execute these filters (including WP default ones, plug-ins filters that were added to the same hook, and your own).
So here, you are using these hooks so you can interfere with WP operations without messing WP core code. You declare the extra operations you wish to execute and you let WP aware of this. WP will then have the courtesy to execute your functions everytime the corresponding hook action or filter is being executed.
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 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.
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.)