I'm overriding the date field to hide the "day" part with this code:

function MYMODULE_form_MYFORM_alter(&$form, FormStateInterface $form_state, $form_id) {
  $form['#after_build'][] = 'MYMODULE_date_remove_day_after_build';

function MYMODULE_date_remove_day_after_build($form, &$form_state) {
  $form['field_MYFIELD']['widget'][0]['value']['day']['#value'] = '15';
  $form['field_MYFIELD']['widget'][0]['value']['day']['#attributes']['class'][] = 'element-hidden';
  return $form;

This hides the day and allows the user to input the month and year. If the field is required, everything is fine.

However, if the field is not required, and the user does not input any value on the form, then the form validation fails because the day of the date field has been set to 15, and the date module validation only accepts "every part (year + month + day) filled out" or "no part filled out."

So, on this specific field in my content type, I want to disable the date module's validation for the "day" alone-- or, I just want to disable validation for the entire date field. How can I do that?


You can achieve this by prepending your own custom #element_validate function before Datelist::validateDatelist().

As in your question, you have to add an after_build function to access the individual parts (year, month, day) of the form element:

function MYMODULE_form_MYFORM_alter(&$form, FormStateInterface $form_state, $form_id) {
  $form['#after_build'][] = 'MYMODULE_date_remove_day_after_build';

You can make the form element disappear by setting '#access' to FALSE. Then prepend your custom #element_validate function to the array #element_validate on the element.

function MYMODULE_date_remove_day_after_build($form, &$form_state) {
  $form['field_MYFIELD']['widget'][0]['value']['day']['#access'] = FALSE;
  array_unshift($form['field_MYFIELD']['widget'][0]['value']['#element_validate'], 'mymodule_date_set_day');
  return $form;

Then in your custom element validate function, unset everything if Year or Month are unset, otherwise, set the day. Notice you have to create the object before passing it to Datelist::validateDatelist().

use Drupal\Core\Form\FormStateInterface;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Datetime\DrupalDateTime;

function mymodule_date_set_day(&$element, FormStateInterface $form_state, &$complete_form) {

  $input = NestedArray::getValue($form_state->getValues(), $element['#parents']);

  if (empty($input['year']) || empty($input['month'])) {
    $form_state->setValueForElement($element, []);
  else {
    $input['day'] = "15";
    $timezone = !empty($element['#date_timezone']) ? $element['#date_timezone'] : NULL;
    $input['object'] = DrupalDateTime::createFromArray($input, $timezone);
    $form_state->setValueForElement($element, $input);
  • 1
    I have updated the answer to list the use statements – oknate Nov 6 '17 at 15:54

Add an additional validation handler that runs before the default one:

array_unshift($form['#validate'], 'MYMODULE_MYFORM_validate');

In this validation handler check if only the day is set, and if so unset it. Something like:

function MYMODULE_MYFORM_validate($form, FormStateInterface $form_state) {
    $field_value = $form_state->getValue('field_MYFIELD');
    if(empty($field_value['month']) && empty($field_value['year'])) {
        $form_state->setValue('field_MYFIELD', []);

I'm totally guessing at some of that syntax. But you should get the idea.

  • I implemented this. kint($form) shows that my validation handler is before the default one, and I also checked that $form_state->setValue() correctly re-sets (unsets) the value... But I'm still getting the error that I need to set the year and month (but not day). – Patrick Kenny Oct 20 '17 at 1:31
  • Hmm, I've not actually used this solution with D8 before. I suspect the problem is with setValue not updating the correct place (values vs input). If you use kint to inspect the available methods of $form_state is there an unset or clear method or something similar? – Felix Eve Oct 20 '17 at 2:07
  • There is unsetValue($key) but setting the field machine name as the argument does not work either. – Patrick Kenny Oct 20 '17 at 2:58

I found that when unsetting a field its easier to set it to the default value of the field.

For example, a select box tends to have the default value of "- Select a Value -". Instead of setting the select boxes value to [] or NULL, Set it to "- Select a Value -". You should take a look at what Drupal would normally set the value of the day field when it is empty and set the field to that value in the form validation. It may be an empty or filled in string, number, bool, array, etc...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.