I'm using a custom multistep form on a node with several date fields spread over multiple steps.
To hide the date fields which should not be visible on certain steps, I use #access=FALSE (just like any other field though).

$form[$field]['#access'] = FALSE;

The outcome is that all date fields are not saved at the end of the multistep form (on node_save)...

A quick and dirty hack is to hide the date fields with HTML instead of using the #access variable.

$form[$field]['#prefix'] = '<div style="display:none;">';
$form[$field]['#suffix'] = '</div>';

However, this little hack causes other functionality not to work properly, for example prefilling the #default_value of a date field using the value of a date field of a previous step.

The following ticket describes possibly related bug: #1144074: does not play well with multistep / does not validate correctly when #access=false

Comments

seddonym’s picture

Title: Dates not saved by #access=FALSE on multistep forms » Dates fields set to #access=FALSE are emptied on save

Renamed the issue from 'Dates not saved by #access=FALSE on multistep forms' as it's a more generic issue.

To reproduce:

- Create a date field and add to a node type.
- In a module, set the #access to user_access('administer nodes') on that date field using hook_form_alter().
- Logged in as a user with administer nodes permission (user 1), create a node and fill in the value of the date field.
- Logged in as a user without administer nodes permission (user 2), edit the node and save.
- Edit the node again as user 1, the value has been wiped.

This issue happens regardless of which widget is used.

(I'm having this issue with the latest development version.)

jover’s picture

Version: 7.x-2.0-alpha4 » 7.x-2.x-dev
Priority: Major » Critical

Didn't knew the problem was so general, but it seems to be correct (so new issue title is better).

seddonym’s picture

For module developers, there's a fairly simple workaround. This isn't working code, just to give an idea:


function MYMODULE_form_alter(&$form, $form_state, $form_id) {
  //Testing here of the form(s) you want to alter
  $form['THE_DATE_ELEMENT']['access'] = user_access('THE_PERMISSION');
  $form['user_cannot_access_date_element'] = array(
    '#type' => 'value',
    '#value' => !user_access('THE_PERMISSION'),
  );

  $form['#validate'][] = '_MYMODULE_date_workaround_validate';
}

function _MYMODULE_date_workaround_validate($form, &$form_state) {
  if ($form_state['values']['user_cannot_access_date_element']) {
    unset($form_state['values']['THE_DATE_ELEMENT']);
  }
}
jover’s picture

I guess this workaround will only work for normal forms, not for multistep forms...
The date values must stay in the $form_state variable, they should only be accessible on one step of the multistep form.

j0rd’s picture

Same problem on a single step form for me. Completely breaking my website as I keep a date field as expiry for paid nodes.

User edits and saves his node, in my system, now he's no longer paid for it.

Gonna have some unhappy people on my site with this one :)

j0rd’s picture

I believe this is caused by a bi-product of this

#408770: #access of date_combo fields prevents validation
http://drupal.org/node/408770#comment-1818564

Also for those looking for information related to #access = FALSE and $form_state['input'] vs. $form_state['values'] take a look at the documentation here: http://api.drupal.org/api/drupal/includes--form.inc/function/form_builder/7

KarenS’s picture

Priority: Critical » Major
Status: Active » Postponed (maintainer needs more info)

A problem that only happens when you do something like create a multi-step form is not a critical bug that makes the module unusable.

When you set #access to false on *any* field you should also be setting #value for that field (move whatever is in #default_value to #value), because the form api won't be processing the value normally.

That may be all that is needed.

das-peter’s picture

I think this is the similar issue like here #1178716-27: Translating node deletes date field entry
Work on patch is in progress.

KarenS’s picture

Status: Postponed (maintainer needs more info) » Closed (duplicate)

See the issues in #1178716: Translating node deletes date field entry, which also was setting #access to false. When that issue is marked fixed it should mean that all the #access issues are fixed.

ben_chad’s picture

Version: 7.x-2.x-dev » 7.x-2.6
Status: Closed (duplicate) » Active

Sorry to resurrect an old bug, but I can confirm this is still an issue in 7.x-2.6. I've double-checked as per #7 that #value and #default_value are set. I'm currently getting around the problem with CSS.

stickywes’s picture

Is it still a problem if you try using the latest dev version?

ben_chad’s picture

No, that sorts it.

maryus88’s picture

I have the same problem. I've set #access to false to a date field and updating to dev version did not fix the problem. I've cleared all caches and run and updb and still nothing.

stickywes’s picture

The way the Date field interacts with the Form API and Field API isn't quite how it should be, so there are certainly still some underlying issues until someone refactors things substantially. My best advice is to use the workaround indicated, especially considering there hasn't been active development on the 7.x branch since 2012.

sylwester’s picture

this still persists in 2.8 and the latest dev as well

leendertdb’s picture

Issue summary: View changes

I'm aware this is an old issue, but we stumbled upon this one today. We are using the field_permissions contrib module, which allows you to specify certain user roles to view/edit a field. For users that do not have the correct permissions, the fields "#access" property will be set to FALSE.

What happened in our case was that after a user with limited permissions edited a node, all hidden field dates were emptied resulting in corrupted data.

I have backtraced the issue to the following code in "./date_popup/date_popup.module":

function date_popup_validate($element, &$form_state) {

  if (date_hidden_element($element)) {
    return;
  }

This if comparison checks if the date field is hidden, and if so, stops executing the validate function which normally takes care of converting a date field array to a string value. When we changed the code above to the following, it worked:

function date_popup_validate($element, &$form_state) {

  if (date_hidden_element($element) && is_string($element['#value'])) {
    return;
  }

Seemed like even though the form element was not rendered, the element itself in hook_node_presave() still contained the date array value, which is not a correct value for the database. So when it tries to insert the array, it errors and simply considers it as an empty string.

The code change above makes sure that it only stops executing the validate function if the form element is hidden AND it is a string. If it is an array, it will keep on executing making sure the array is converted to a string value (what normally always happens when the form element is actually rendered).

leendertdb’s picture

Status: Active » Needs review

Updating status to "Needs review". I was unable to create a patch at the moment, but perhaps someone else could do that after verifying the fix above works.

kingandy’s picture

Version: 7.x-2.6 » 7.x-2.10
Status: Needs review » Active

The code I'm looking at has that if (date_hidden_element($element)) immediately followed by an if (is_string($element['#value'])), so I don't think adding it to the first logic will have any effect. This seems to have been in place since at least 7.x-2.1 (2012). @leeendertdb, are you on the 1.x branch? It seems like this may already have been implemented.

TBH the #access=false seems to prevent the field from being validated at all (which seems reasonable) so I don't think the problem is in the validation function.

I'm still seeing this behaviour in the 7.x-2.10 release (under Drupal 7.54). We're manually applying #access=false, and the save function is producing a second null-null date range in the field (thankfully retaining the original from-to values in delta 0).