Drupal 8: Use Custom Submit Handler for Theme Settings Form

In Drupal 8, adding an extra submit handler for a theme settings form is not that straight forward as for normal forms. The extra submit handler put in normal way will not get called and PHP warning messages may get thrown. Fortunately there is an easy trick to overcome that issue that I show in this post.

We will get warning message like this when try to add submit handler in normal way:

Warning: call_user_func_array() expects parameter 1 to be a valid callback, function 'MY_THEME_form_system_theme_settings_submit' not found or invalid function name in Drupal\Core\Form\FormSubmitter->executeSubmitHandlers() (line 111 of core/lib/Drupal/Core/Form/FormSubmitter.php).

It does not work in normal way, because we will be usually on admin theme while modifying settings for our particular theme and on submission the theme's .theme file will not be loaded normally where we will be keeping our submit handler.

Assuming theme's name as MY_THEME. We need to add path of theme's .theme file in list of files to be loaded, kept in form build info. When form submission is being processed those files will be loaded and it can detect our submit handler.

/**
 * Implements hook_form_system_theme_settings_alter().
 */
function MY_THEME_form_system_theme_settings_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state) {
  $theme_file = drupal_get_path('theme', 'MY_THEME') . '/MY_THEME.theme';
  $build_info = $form_state->getBuildInfo();
  if (!in_array($theme_file, $build_info['files'])) {
    $build_info['files'][] = $theme_file;
  }
  $form_state->setBuildInfo($build_info);

  $form['#submit'][] = 'MY_THEME_form_system_theme_settings_submit';
}

function MY_THEME_form_system_theme_settings_submit(&$form, \Drupal\Core\Form\FormStateInterface $form_state) {
  // TODO: Extra submssio logic.
  // This submit handler will be called before default submit handler for this form.
}

Please note that you have to attach the submit handle to submit button in case there is already a submit handler attached to the submit button. Above sample will work with default Drupal 8 setup.