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.
      file_save($image);
      // 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.

Disclaimer

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

Adding classes to the Drupal image_formatter link

So you are using Drupal, and you are outputting an image field from a node to the screen.  You have it set up so that the display is using an image_style to generate a thumbnail, and you are linking to the full size image.  All great, except you want an additional class on the link….

You could override the field template so that it has the field hard coded.  Seems like a bit of hard work, and massively redundant since all you want is a single (or couple of) class(es) on the link (as you’re using a Bootstrap based theme and want to add the thumbnail class)

Preprocess this

Enter theme_preprocess_field(), which is called before any field is rendered, and is your friend.

First thing to do is target the field that you are looking to modify, which is done like this

function THEME-NAME_preprocess_field(&$variables, $hook) {
  if ($variables['element']['#field_name'] == 'field_FIELD-NAME') {
    ...
  }
}

Next thing is to add the class to the link.  The image formatter uses items from the #path array to construct and link, and makes use of the l() function, so we need to bare that in mind when we are adding classes.  The option array with the #path array gets passed into the l function as the options parameter.

The final code looks like this.

function THEME-NAME_preprocess_field(&$variables, $hook) {
  if ($variables['element']['#field_name'] == 'field_FIELD-NAME') {
    foreach ($variables['item'] as &$item) {
      $item['#path']['options']['attributes']['class'] = array(
        'my-class',
      );
    }
  }
}

So there we have it, our class is added to the link, in just a few lines of code, without overriding a template that could easily get stale or hard to maintain.

Theming WordPress using Thematic and Compass

Recently I have started to play with making my own themes for WordPress. Rather than start from the ground and reinvent the wheel, I decided to use a base theme which I can then extend. I also opted to use the brilliant Compass css framework to speed up development. Im going to talk about how I set my project up to get the most out of these tools.

Continue reading Theming WordPress using Thematic and Compass