I am working on a Drupal site that needs to have a 'careers' page. I have a list of twenty or so jobs, and 30 or so locations where these jobs may be available.
What I am looking to do is make it so, when a job becomes available, all that needs to be done is the user selects the job title and the location where it is available and it will create the posting with the job description and other info I have along with the info for that location.
Another hurtle I am running into is making it so I can have multiple instances... ex. If the same job is available at two or more locations.
I have been trying to wrap my mind around how I am going to make this work and am coming up blank. If anyone has an idea to point me in the right direction, it would be appreciated.
Sounds like a pretty common use case; if it was me I'd approach it like this:
Create a 'Job' content type
Add a new 'Location' Vocabulary
Add a term reference field on the 'Job' content type to the 'Location' vocabulary, with unlimited values (or the maximum no. of locations you want to allow per job).
Create a custom form for your admins, something like:
function MYMODULE_add_job_form($form, &$form_state) {
$form['title'] = array(
'#type' => 'textfield',
'#title' => t('Title'),
'#maxlength' => 255,
'#required' => TRUE
);
// Load the vocabulary (the machine name might be different).
$vocabulary = taxonomy_vocabulary_machine_name_load('location');
// Get the terms
$terms = taxonomy_get_tree($vocabulary->vid);
// Extract the top level terms for the select options
$options = array();
foreach ($terms as $term) {
$options[$term->tid] = $term->name;
}
$form['locations'] = array(
'#type' => 'select',
'#title' => t('Locations'),
'#options' => $options,
'#multiple' => TRUE,
'#required' => TRUE
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Add job')
);
return $form;
}
Create a custom submit handler for the form to add the new node programatically:
function MYMODULE_add_job_form_submit($form, &$form_state) {
$location_tids = array_filter($form_state['values']['locations']);
$node = new stdClass;
$node->type = 'job';
$node->language = LANGUAGE_NONE;
node_object_prepare($node);
$node->title = $form_state['values']['title'];
$node->field_location_term_ref[LANGUAGE_NONE] = array();
foreach ($location_tids as $tid) {
$node->field_location_term_ref[LANGUAGE_NONE][] = array(
'tid' => $tid
);
}
node_save($node);
$form_state['redirect'] = "node/$node->nid";
}
You'll need to add a page callback for that form obviously, and there'll likely be some small changes you'll need to make (names of fields etc), but it should give you a good starting point. You'll also need to load the location taxonomy terms at some point to extract the description info you mentioned...you can use taxonomy_term_load() to do that.
Related
I have a form in Drupal that calls an external database in Netezza. Retrieve this data from Netezza lasts about 10 seconds. Then, based on that information I have to build a select control to let the user choose from a list of categories. When the user chooses a category I do another expensive call to Netezza to retrieve more information.
The problem is that for the second interaction (when the user chose a category) the form is reprocessed and therefore doing 2 expensive calls to Netezza, not one as anyone would expect or desire.
Do you know a workaround for this situation? Is there a way to do an ajax call using the Drupal Ajax Framework without rebuilding the entire form?
Thanks.
PD: Reading documentation about the Ajax Framework I guess a solution could be using another path specifiying #ajax['path'], but havenĀ“t fully tested that behavior and will be thankful if you share your experience.
PD2: I would prefer a workaround based on the Drupal Ajax Framework, not in a caching mechanism.
I'd highly recommend you to have a look into Drupal Examples, specially the module called ajax_example.
this is a fast sample code, might not be running, but just to give you the idea
function expensive_form($form, &$form_state) {
$form['category'] = array(
'#title' => t('Cateogry'),
'#type' => 'select',
'#options' => first_expensive_operation(),
'#ajax' => array(
'callback' => 'choose_category_callback',
'wrapper' => 'ajax-div',
// 'method' defaults to replaceWith, but valid values also include
// append, prepend, before and after.
// 'method' => 'replaceWith',
// 'effect' defaults to none. Other valid values are 'fade' and 'slide'.
'effect' => 'slide',
// 'speed' defaults to 'slow'. You can also use 'fast'
// or a number of milliseconds for the animation to last.
// 'speed' => 'slow',
),
);
$form['ajax_fieldset'] = array(
'#title' => t("Ajax Fields"),
// The prefix/suffix provide the div that we're replacing, named by
// #ajax['wrapper'] above.
'#prefix' => '<div id="ajax-div">',
'#suffix' => '</div>',
'#type' => 'fieldset',
'#description' => t('This is where we get automatically updated something'),
);
// this will only be executed on the second run of the form
// when the category is set.
if (isset($form_state['values']['category'])) {
$form['ajax_fieldset']['something'] = array(
'#title' => t('Somethings'),
'#type' => 'select',
'#options' => second_expensive_operation($form_state['values']['category']),
);
}
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Submit'),
);
return $form;
}
/**
* Callback element needs only select the portion of the form to be updated.
* Since #ajax['callback'] return can be HTML or a renderable
* array, we can just return a piece of the form.
*/
function choose_category_callback($form, $form_state) {
return $form['ajax_fieldset'];
}
Hi i have used this code
<?php
$elements = drupal_get_form("user_login");
$form = drupal_render($elements);
echo $form;
?>
to get the default Drupal login form for my site but I need to customize the HTML, I have found some pages in module/users but did not understand how to customize the structure.
The user login form for Drupal is built by the user_login function in user.module using Drupal Form API. If you need to customize it, you should do it using hook_form_alter() in your module
function YOUR_MODULE_NAME_form_alter(&$form, &$form_state, $form_id) {
if ($form_id=='user_login') {
// YOUR CUSTOM CODE FOR THE FORM GOES HERE
}
}
** EDIT, AFTER YOUR COMMENT **
You don't need to call the YOUR_MODULE_NAME_form_alter() function: Drupal does that for you via the hook mechanism everytime it needs to build a form, and, when $form_id=='user_login', it modifies the login form to allow your customization. The way Drupal does that is discussed in detail in drupal.org, just follow the link I wrote at the beginning of this answer.
The user login form is declared this way in user.module:
// Display login form:
$form['name'] = array('#type' => 'textfield',
'#title' => t('Username'),
'#size' => 60,
'#maxlength' => USERNAME_MAX_LENGTH,
'#required' => TRUE,
);
$form['name']['#description'] = t('Enter your #s username.', array('#s' => variable_get('site_name', 'Drupal')));
$form['pass'] = array('#type' => 'password',
'#title' => t('Password'),
'#description' => t('Enter the password that accompanies your username.'),
'#required' => TRUE,
);
$form['#validate'] = user_login_default_validators();
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Log in'));
The $form array is passed by reference to your hook_form_alter() before being rendered, allowing for customization. So, let's say that you want to change the label of the textfield for the user name from "Username" to "Name of the User", you write
$form['name']['#title'] = t("Name of the User");
in your custom code. If you want to add another field to the form (a textarea, for example), you do
$form['otherfield'] = array(
'#title' => t('My new custom textarea'),
'#type' => 'textarea',
'#description' => t("A description of what this area is for"),
'#cols' => 10,
'#rows' => 3,
'#weight' => 20,
);
and Drupal will add the field to the user login form.
There are many different kind of fields and properties that you can customize this way: I encourage you to fully read the Form API documentation. This way you let Drupal take care of form generation, translation, rendering, validation and submission, also permitting to other modules to manipulate your form if needed.
I hope it's clear, have a good day.
use this in template.php
function themename_theme() {
$items = array();
$items['user_login'] = array(
'render element' => 'form',
'path' => drupal_get_path('theme', 'corporateclean') . '/templates',
'template' => 'user-login',
);
and create a template folder and within that create a file user-login.tpl.php and in this file you can put your html and could customize drupal login
I've constructed a custom module to create a form. Now I'm stuck on the theming. I already have a CSS stylesheet for the form, since my company is part of the government and they have a preset branding. So I wanted to change the HTML used by the default form theme functions of Drupal thus implementing the correct style.
But only the form-tag of the form gets rendered. The fieldset and elements are not rendered. When the theme functions are removed the default theming kicks in and the form renders normally (but of course without the requested theming).
What I have tried so far:
Added a hook_theme function to add theme functions
function publicatieaanvraagformulier_theme() {
return array(
'publicatieaanvraagformulier_form' => array(
'arguments' => array("element" => NULL)
),
'publicatieaanvraagformulier_fieldset' => array(
'arguments' => array("element" => NULL)
),
'publicatieaanvraagformulier_form_element' => array(
'arguments' => array(
"element" => NULL,
"value" => NULL
)
)
);
}
Added ['#theme'] to the form-element, fieldset-element and the form-elements
$form['#theme'] = "publicatieaanvraagformulier_form";
$form['groep'] = array(
'#title' => t("Please fill in your details"),
'#type' => "fieldset",
'#theme' => "publicatieaanvraagformulier_fieldset"
);
$form['groep']['organisatie'] = array(
'#title' => t("Organization"),
'#type' => "textfield",
'#attributes' => array("class" => "text"),
'#theme' => "publicatieaanvraagformulier_form_element"
);
Added the actual theme function based on the default ones in form.inc
function theme_publicatieaanvraagformulier_form($element) {
function theme_publicatieaanvraagformulier_fieldset($element)
function theme_publicatieaanvraagformulier_form_element($element, $value)
I haven't included the code of these functions because even with the default themefunctions code, they don't work. Therefor I assume they are not the source of the problem.
The form is called
//Get the form
$form = drupal_get_form('publicatieaanvraagformulier');
//Add messages
$errors = form_get_errors();
if (!empty($errors)) {
$output .= theme("status_messages","error");
}
//Show form
$output .= $form;
return $output;
I haven't found similar 'complicated' examples of theming a form, but have pieced together the former from books and online searches.
Hopefully someone has an answer to this problem (point out the mistake I made).
Greetings
Jeroen
First post on stack overflow... so go easy on me!
There doesn't seem to be a suitable solution to the Drupal FAPI multiple callback issue for simple form submissions.
THE PROBLEM: My form, when submitted, adds two entries to the respective database table. Given that there is only one call to add it to the database, I feel it's safe to assume that the query is run twice (hence the dual entries).
The following code may help to provide a basis for a solution. Oh, it's Drupal 7 too, so documentation is still very much D6 centric.
function mymodule_sidebar_form_add_submit(&$form, &$form_state) {
$form_values = $form_state['values'];
$se_title = check_plain(trim($form_values['title']));
$se_link = url(trim($form_values['link']));
$se_content = check_plain(trim($form_values['content']));
$se_image = isset($form_values['image']) ? $form_values['image'] : '';
// The multi-line part below is actually a single line the real code
$query = sprintf("INSERT INTO sidebar_element(title, image_url, content)
VALUES ('%s', '%s', '%s');", $se_title, $se_image, $se_content);
db_query($query);
drupal_set_message(t('Sidebar Element has been added successfully.'));
}
... and my form function contains a submit button:
$form['submit'] = array(
'#value' => t('Add Sidebar'),
'#type' => 'submit',
'#title' => t('Add Sidebar'),
'#submit' => array('mymodule_sidebar_form_add_submit'),
);
I guess the questions I need answered are:
Why is there a double callback in the first place?
Is there a way to identify the first callback?
Thanks in advance to all.
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Save')
);
$form['#submit'] = array('my_form_submit');
And replace
// The multi-line part below is actually a single line the real code
$query = sprintf("INSERT INTO sidebar_element(title, image_url, content)
VALUES ('%s', '%s', '%s');", $se_title, $se_image, $se_content);
db_query($query);
with
// The multi-line part below is actually a single line the real code
$query = "INSERT INTO {sidebar_element} (title, image_url, content)
VALUES ('%s', '%s', '%s')";
db_query($query, $se_title, $se_image, $se_content);
For Drupal 7
// Add the buttons.
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array(
'#type' => 'submit',
'#access' => my_func(),
'#value' => t('Save'),
'#weight' => 100,
'#submit' => array('my_form_submit'),
);
As example read node_form() code
To find out where the second call is coming from, the easiest way is to install devel.module and use ddebug_backtrace() in your submit callback. You might need to disable the HTTP redirecto to see it, too (exit()).
But more importantly, use the API, Luke!
<?php
db_insert('sidebar_element')
->fields(array(
'title' => $se_title,
'image_url' => $se_image,
'content' => $se_content,
))
->execute():
?>
This is how your insert query should look like, what you are doing is insecure!
And for SELECT, use db_query() with named placeholders:
<?php
$result = db_query('SELECT * FROM {sidebar_element} WHERE title = :title', array(':title' => $something));
?>
Modifying download_count module to include information about users who downloaded files. Want to show this info on users' profile pages.
Here's the code:
function download_count_user($op, &$edit, &$account, $caterory = NULL) {
if ($op == 'view')
{
$result = db_query("SELECT filename FROM file_downloads_users WHERE user_id = %d", $account->uid);
while ($file_array = db_fetch_object($result)) {
$file_str .= $file->filename . '<br/>';
}
$items['downloads'] = array(
'title' => t('Files'),
'value' => $file_str,
'class' => 'member'
);
return array(t('Downloads')=>$items);
}
}
Doesn't give me any errors but doesn't show anything on My Account page either.
You don't want to modify a module. Drupal is built very very carefully to avoid having to hack core or contrib. Unless of course you are contributing a patch back.
The right way is to build your own custom module to do this (that would require the user downloads module) and implement the hook almost exactly what you're doing here.
The function is getting run (module enabled, var_dump ing or krumo'ing causes output?, cache cleared)
The way you are keying your variables is for Drupal 5.x and below. In D6, you add to $account->content. Which version of drupal are you using?
Check out user_user() (in user.module):
$account->content['user_picture'] = array(
'#value' => theme('user_picture', $account),
'#weight' => -10,
);
$account->content['summary']['file_downloads'] = array(
'#type' => 'user_profile_item',
'#title' => t('File Downloads'),
'#value' => $file_str,
'#weight' => 1
);