6 hours

Managed file upload in Drupal theme settings

So you want to add a managed file field to your theme settings to allow for an additional logo, great! Using FAPI and a theme-settings.php file it will be a piece of cake.  Not so fast….

The sticking point here is that a managed file once uploaded has to have its status changed to 1 to make it persist.  If you don’t change that status then cron will come along and merrily remove it after 6 hours, leaving you with a broken image on your theme.

Add the field to the theme settings in the usual way

MYTHEME_form_system_theme_settings_alter(&$form, $form_state) {
  $form['secondary_logo'] = array(
    '#title' => t('Secondary logo'),
    '#description' => t('A description'),
    '#type' => 'managed_file',
    '#upload_location' => 'public://secondary-logo/',
    '#upload_validators' => array(
      'file_validate_extensions' => array('gif png jpg jpeg'),
    '#default_value' => theme_get_setting('secondary_logo'),

This gets the field on the settings screen, but doesn’t allow you to persist by altering the status.  On any normal form you could use hook_form_submit(), but unfortunately this does not work with theme settings.

The fix is to add a custom submit handler to the form, but due to a bug in the theme settings system you need to specify your theme settings file as a dependency.  Add the following to the MYTHEME_form_system_theme_settings_alter function

$form['#submit'][] = 'MYTHEME_settings_form_submit';

// Get all themes.
$themes = list_themes();
// Get the current theme
$active_theme = $GLOBALS['theme_key'];
$form_state['build_info']['files'][] = str_replace("/$active_theme.info", '', $themes[$active_theme]->filename) . '/theme-settings.php'

It is important to note that as you are now altering the $form_state variable you need to add an & to the parameter so that it is passed by reference.

Now you can create the submit handler to actually change the status of the file.

function MYTHEME_settings_form_submit(&$form, $form_state) {
$image_fid = $form_state['values']['secondary_logo'];
  $image = file_load($image_fid);
  if (is_object($image)) {
    // Check to make sure that the file is set to be permanent.
    if ($image->status == 0) {
      // Update the status.
      $image->status = FILE_STATUS_PERMANENT;
      // Save the update.
      // Add a reference to prevent warnings.
      file_usage_add($image, 'MYTHEME', 'theme', 1);

And there you have it, you should be able to keep hold of your file for longer than 6 hours.


I was put on the right track to this solution and have used code from this stack overflow question.

11 thoughts on “Managed file upload in Drupal theme settings”

  1. Hello Thank you for this. Altough there are some errors here it pointed me in the irhgt direction.

    In MYTHEME_form_system_theme_settings_alter you dont have the reference sign in here (but nice that you mention this is important it is what was missing on my part)

    Next to $form[‘#submit’][] = ‘MYTHEME_settings_form_submit’;

    There are a couple of “)” and “;” missing. Might be a bad copy paste.

    Anyway saved my day! this addresses btw a serious bug in Drupal core system https://drupal.org/node/1862892 : “When theme-settings.php has a managed_file field and a submit callback, ” Call to undefined function” error is thrown”

    I am posting a reply here maybe this helps someone in the future;)

    best regards,

  2. Both of you are legends, thanks for this! So for others, your function should be:
    MYTHEME_form_system_theme_settings_alter(&$form, &$form_state)


  3. When I try this, I get “Parse error: syntax error, unexpected ‘$form_state’ (T_VARIABLE)” for line 125 of my theme-settings.php file. Line 125 is:
    $form_state[‘build_info’][‘files’][] = str_replace(“/$active_theme.info”, ”, $themes[$active_theme]->filename) . ‘/theme-settings.php’

    Any thoughts?

  4. Hi, I’ve tried using your code, as it seems like it will solve the problem I’m running into.

    I can’t get it to work. First, there is still a semicolon missing at the end of this line:

    $form_state[‘build_info’][‘files’][] = str_replace(“/$active_theme.info”, ”, $themes[$active_theme]->filename) . ‘/theme-settings.php’

    Even if I add the semicolon, the code fails with the same error (undefined function).

    Is this working for anyone?

Leave a Reply