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.





12 responses to “Managed file upload in Drupal theme settings”

  1. joaogarin Avatar

    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. wsluimer Avatar

    This is exactly what I was missing out on. Persisting a field is not something I came up with myself. Thanks for sharing thoughts and code!

  3. Shaun Avatar

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


  4. Marshal Banana Avatar
    Marshal Banana

    Thanks a lot for this.

  5. Anima Avatar

    It works perfectly, but after changing status file couldn’t be removed from folder and DB 🙁

  6. Kevin Cull Avatar

    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?

    1. Kevin Cull Avatar

      Never mind. The code was just missing semicolons on that line and the line before it. I should have picked up on that from joaogarin’s comment.

      1. ghosty Avatar

        Cheers, I have amended the code to prevent that from happening to anyone one else.

  7. Sleepy Dog Avatar
    Sleepy Dog

    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?

  8. Luke Joliat Avatar
    Luke Joliat

    How can I get the path to the uploaded file into a twig variable?

  9. andyanderso Avatar

    For those of you looking into how to get the path of your image you can use the following:
    $secondary_logo = file_create_url(file_load(theme_get_setting(‘secondary_logo’))->uri);

Leave a Reply