How to override form action in Drupal? - drupal

I originally started this question in another thread, but that thread was sorta, kinda answered, and now I primarily want to know how to specify another form action... I tried using the code below, but the form action, when output, remains unchanged, although looking at the print_r($form), it's correctly changed... Why isn't it picking up?
function mytheme_user_profile_form($form) {
global $user;
$uid = $user->uid;
//print '<pre>'; print_r($form); print '</pre>';
$category = $form['_category']['#value'];
switch($category) {
case 'account':
$form['#action'] = '/user/'.$uid.'/edit?destination=user/'.$uid;
break;
case 'education':
$form['#action'] = '/user/'.$uid.'/edit/education?destination=user/'.$uid;
break;
case 'experience':
$form['#action'] = '/user/'.$uid.'/edit/experience?destination=user/'.$uid;
break;
case 'publications':
$form['#action'] = '/user/'.$uid.'/edit/publications?destination=user/'.$uid;
break;
case 'conflicts':
$form['#action'] = '/user/'.$uid.'/edit/conflicts?destination=user/'.$uid;
break;
}
//print '<pre>'; print_r($form); print '</pre>';
//print $form['#action'];
$output .= drupal_render($form);
return $output;

hook_form_alter() is likely the way to go.
Here are some hopefully helpful links:
Form Theming: How do I set $form['action']?
Modifying Forms in Drupal 5 and 6
hook_form_alter
EDIT: reply to comment #1 below:
How to implement hook_form_alter():
You must create a module (you cannot use template.php). It's easier than it looks.
For a module named "formstuff", you would create formstuff.info and formstuff.module and put them in either sites/all/modules or sites/yoursitename/modules. Set up the .info and .module files per the instructions, then just create the following function in your .module file:
function formstuff_form_alter(&$form, $form_state, $form_id) {
// do stuff
}
This function is a hook because it is named properly (i.e. replace the word 'hook' with the name of your module), and it matches hook_form_alter's function signature (i.e. it takes the same parameters).
Then just enable your module in your site's admin and the hook should do it's magic.
Note that hook_form_alter takes a reference to the form; this allows you to modify it in-place.

You need to put the form_alter function in a module and then use either if or switch to check the form ID. If the form ID is the one you want to alter then give the form an action property
$form['someID'] = array(
'#action' => 'path/you/want',
);

Related

In Drupal 6 What is the hook I would use to override user_pas_submit?

I need some additional functionality added to user_pass_submit. This must be added without changing the core. What is the hook I would use to do this?
Thanks.
You should be able to use hook_form_FORM_ID_alter() to replace the submit handler for the user_pass form with your own module's copy of user_pass_submit, altered as necessary.
Something like this...
function MODULE_form_user_pass_alter(&$form, &$form_state) {
$form['#submit'] = array('MODULE_user_pass_submit');
}
function MODULE_user_pass_submit($form, &$form_state) {
global $language;
$account = $form_state['values']['account'];
// Mail one time login URL and instructions using current language.
_user_mail_notify('password_reset', $account, $language);
watchdog('user', 'Password reset instructions mailed to %name at %email.', array('%name' => $account->name, '%email' => $account->mail));
drupal_set_message(t('Further instructions have been sent to your e-mail address.'));
$form_state['redirect'] = 'user';
return;
}
Of course, this falls down if you have multiple modules trying to do

WP Settings API save to multiple options

In the Wordpress Settings API, creating a new options page usually starts out with
register_setting('sample_options', 'my_option');
add_settings_section('section', 'Sample Options', 'callback1', 'page');
add_settings_field('name', 'Label', 'callback2', 'page', 'section');
In this simplified example, the data gets saved in the option my_option making the value of name accessible through
$option = get_option('my_option');
$name = $option['name']; // Got it
But what if the value of the name field is there not to place a new value but to update an already existing option that's not my_option like for example this_other_option? I guess what I'm really looking for is is it possible for one field to save to multiple options (my_option and this_other_option) while using the Settings API?
I suppose you could use a callback in register_setting. It would look something like the following:
<?php
register_setting('sample_options', 'my_option', 'my_sanitize_callback');
function my_sanitize_callback($value, $option) {
$value = mysql_real_escape_string($value);
update_option('my_other_option', $value);
return $value;
}
?>
You may have to tweak that a bit. I haven't tested it.

Removing [nid:n] in nodereference autocomplete

Using the autocomplete field for a cck nodereference always displays the node id as a cryptic bracketed extension:
Page Title [nid:23]
I understand that this ensures that selections are unique in case nodes have the same title, but obviously this is a nasty thing to expose to the user.
Has anyone had any success in removing these brackets, or adding a different unique identifier?
Ultimately, you need to change the output of nodereference_autocomplete() in nodereference.module.
To do this properly, you want a custom module to cleanly override the function.
This function is defined as a menu callback, thus,
/**
* Implementation of hook_menu_alter().
*/
function custom_module_menu_alter(&$items) {
$items['nodereference/autocomplete']['page callback'] = 'custom_module_new_nodereference_autocomplete';
}
Then, copy the nodereference_autocomplete function into your custom module, changing it's name to match your callback. Then change this one line:
$matches[$row['title'] ." [nid:$id]"] = '<div class="reference-autocomplete">'. $row['rendered'] . '</div>';
Dropping the nid reference.
$matches[$row['title']] = '<div class="reference-autocomplete">'. $row['rendered'] . '</div>';
I believe the identifier is purely cosmetic at this point, which means you could also change the text however you like. If it is not purely cosmetic, well, I haven't tested to see what will happen in the wrong conditions.
I always meant to identify how to do this. Thank you for motivating me with your question.
What Grayside has posted will work... as long as you don't have two nodes with the same title. In other words, if you want to do as Grayside has proposed, you need to be aware that the nid is not entirely unimportant. The nodereference_autocomplete_validate() function does two things. It checks to see if there is a node that matches, and if so, it passes the nid on, setting it to the $form_state array. If it can't find a node, it will set an error. If the nid is present, it will be used to get the node, which also is faster, the code is here:
preg_match('/^(?:\s*|(.*) )?\[\s*nid\s*:\s*(\d+)\s*\]$/', $value, $matches);
if (!empty($matches)) {
// Explicit [nid:n].
list(, $title, $nid) = $matches;
if (!empty($title) && ($n = node_load($nid)) && $title != $n->title) {
form_error($element[$field_key], t('%name: title mismatch. Please check your selection.', array('%name' => t($field['widget']['label']))));
}
}
This just checks to see if there is a nid and checks if that node matches with the title, if so the nid is passed on.
The 2nd option is a bit slower, but it is here errors can happen. If you follow the execution, you will see, that if will try to find a node based on title alone, and will take the first node that matches. The result of this, is that if you have two nodes with the same title, one of them will always be used. This might not be a problem for you, but the thing is, that you will never find out if this happens. Everything will work just fine and the user will think that he selected the node he wanted to. This might be the case, but he might as well have chosen the wrong node.
So in short, you can get rid of the nid in the autocomplete callback, but it has 2 drawbacks:
performance (little)
uncertainty in selecting the correct node.
So you have to think about it, before going this route. Especially, since you most likely wont be able to find the problem of the selection of the wrong nodes, should it happen. Another thing to be aware of, is that the nid showing up, also brings some valuable info to the users, a quick way to lookup the node, should they be in doubt if it is the one they want, if several nodes have similar titles.
I got Grayside's answer to work, but I had to use MENU alter, instead of the FORM alter he posted. No biggy!
function custommodule_menu_alter(&$items) {
$items['nodereference/autocomplete']['page callback'] = 'fp_tweaks_nodereference_autocomplete';
}
I've found an alternative solution is to change your widget type to select list and then use the chosen module to convert your list to an autocomplete field.
This handles nodes with the same title, and actually I think the UI is better than the one provided by the autocomplete widget.
To anyone coming across this (rather old) topic by way of a google search - for Drupal 7 please consider using entityreference module and "Entity Reference" field type if possible.
You can acheive a lot more in configuration with an "Entity Reference" field. It doesn't have this problem with the nid in square brackets.
Here is the full Drupal 7 version (References 7.x-2.1) of Grayside's answer. This goes in your custom module:
/**
* Implementation of hook_menu_alter().
*/
function custom_menu_alter(&$items) {
$items['node_reference/autocomplete/%/%/%']['page callback'] = 'custom_new_node_reference_autocomplete';
}
/**
* Implementation of Menu callback for the autocomplete results.
*/
function custom_new_node_reference_autocomplete($entity_type, $bundle, $field_name, $string = '') {
$field = field_info_field($field_name);
$instance = field_info_instance($entity_type, $field_name, $bundle);
$options = array(
'string' => $string,
'match' => $instance['widget']['settings']['autocomplete_match'],
'limit' => 10,
);
$references = node_reference_potential_references($field, $options);
$matches = array();
foreach ($references as $id => $row) {
// Markup is fine in autocompletion results (might happen when rendered
// through Views) but we want to remove hyperlinks.
$suggestion = preg_replace('/<a href="([^<]*)">([^<]*)<\/a>/', '$2', $row['rendered']);
// Add a class wrapper for a few required CSS overrides.
$matches[$row['title']] = '<div class="reference-autocomplete">' . $suggestion . '</div>'; // this is the line that was modified to remove the "[nid:XX]" disambiguator
}
drupal_json_output($matches);
}

Drupal: Access $profile from a block

I'm trying to get the avatar (profile picture) located in the $profile array to appear in a BLOCK. The variable $profile is not accessible from blocks. It's scope is only in that actual user-profile.tpl.php file. So... does anybody know how I can execute something like this:
print $profile[user_picture];
in a drupal BLOCK?
I figured i might as well post it here as well. See my second comment on the first thread in this discussion. Below is my code I used with INSERT VIEW to get what I wanted:
<?php
$profileUser = "";
if (arg(0) == "user") {
$profileUser = arg(1);
}
// removed some other checks i do to populate $profileUser
?>
[view:VIEWED_PROFILE_AVATAR=block=<?php print $profileUser; ?>]
I hope that helps someone.
You can try using the following code in a new block (admin/build/block/add):
<?php
global $user;
$output = theme_image($user->picture, $alt = 'user pic', $title = 'user pic');
print $output;
This gives you access to the global $user variable and then you can use the picture property to get the URL for the current users profile picture.

Custom logic for exposed filters in a Drupal view

I'm working on a Drupal site and would love some advice on this. Currently, a user enters his level for a number of different skills. This is stored in a CCK integer field and exposed to the user as a drop-down widget containing the key/value pairs 1|Beginner, 2|Intermediate, 3|Advanced.
In a view, I expose the allowed values for each skill, which are presented to the user as checkboxes (using the Better Exposed Filters module) and then listed in a sortable table. In practice, users generally search for people who have "at least knowledge level X in skill Y". Is there a module or straightforward way to display the allowed values as a drop-down and use a "greater than" operator in the query instead of a "one of"?
Any sample code or advice on how to dynamically change the filter logic or the WHERE clause of the query would be very appreciated.
You want to use hook_views_query_alter(), while I haven't specifically altered the WHERE clause, I have altered the SORTBY clause and the idea behind both should be relatively similar.
Here's a quick piece of code:
function my_module_views_query_alter(&$view, &$query) {
switch ($view->name) {
case 'view1':
$args = _my_module_get_querystring();
switch ($args['condition']) {
case 'condition1':
$query->where[0]['args'][0] = 1;
break;
case 'condition2':
$query->where[0]['args'][0] = 2;
break;
}
break;
}
}
/**
* Returns querystring as an array.
*/
function _my_module_get_querystring() {
$string = drupal_query_string_encode($_REQUEST, array_merge(array('q'), array_keys($_COOKIE)));
$args = explode('&', $string);
foreach ($args as $id => $string) {
unset($args[$id]);
$string = explode('=', $string);
$args[$string[0]] = str_replace(' ', '-', $string[1]);
}
return $args;
}
This particular piece would allow you to alter the WHERE clause using a querystring (?condition=condition1), but you could alter it to get the arguments however you wish.
Hope this helps.
Using Decipher's sample and spending a few hours reading up and playing around, I've gotten a basic module that works perfectly for my needs. Thanks again!
Here's my code if anyone else comes across a similar need:
<?php
// $Id$
/**
* #file
* Module for modifying the views query to change an EQUALS
* to a GREATER THAN for specific filters.
*/
function views_greater_than_views_query_alter(&$view, &$query) {
//only implement for views that have Search in their name
if(strstr($view->name, "search")) {
$whereclauses = $query->where[0]['clauses'];
foreach ($whereclauses as $i=>$currentrow) {
$currentrow = str_replace('= %d', '>= %d', $currentrow);
$query->where[0]['clauses'][$i] = $currentrow;
}
unset($whereclauses);
}
}

Resources