The formatter plugin system is powerful but impenetrable for front-end (and many back-end) developers. For use cases involving storing addresses from a single country or certain select countries, it's overkill to have to create a module and implement a custom ctools plugin.

One way to address this would be to provide an alternate field formatter that implements a theme function, which can then be overridden conventionally in modules and themes.

Comments

les lim’s picture

StatusFileSize
new3.73 KB

Here's a patch that implements the above suggestion. The actual theme_addressfield_address() function provided here is extremely basic and was built with US addresses in mind. This should probably be expanded, but the key feature here to have something that can be overridden in the first place.

les lim’s picture

Status: Active » Needs review

Changing status.

thirdboxcar’s picture

Thank you, works perfectly for my needs!

amarcus’s picture

Also, look at the addressfield_tokens module. It provides several theme functions:

  • theme_addressfield_formatter: Renders an address using the default generator associated with the given handler (the ctools plugin name).
  • theme_addressfield_formatter__citystate: Renders only the city, state and country separated by commas
  • theme_addressfield_formatter__linear: Renders each of the addressfield components as single line, separated by commas.
RobW’s picture

I'm looking for this too so I can easily theme with microdata (not microformats, which others are working on a field formatter for I believe). Will test the patch, thanks for starting on this Les Lim.

mrweiner’s picture

I had this working on a local dev version of my site running 7.12, but after uploading it to the server, with version 7.14, this theme function stopped working. It's not even displaying in the list of display format options. Any suggestions?

les lim’s picture

mrweiner: try clearing your caches.

mrweiner’s picture

I've cleared my caches multiple times and have also ran update.php as somebody else suggested. I'm quite baffled.

rich.3po’s picture

Agree that themeing address fields is far more convoluted than it needs to be.

For the time being, the addressfield_tokens approach suggested in #4 worked well for me. You can set the field formatter to 'One line' (in my case, in Views), then you have the option to override theme_addressfield_formatter__linear() if the default markup is not quite right.

Cheers

askibinski’s picture

patch works perfectly, thanks!

infines’s picture

Status: Needs review » Reviewed & tested by the community
joelcollinsdc’s picture

This patch is like an island of simplicity emerging from a sea of complexity. Thank you.

big_smile’s picture

How do you use this patch?

I have installed the patch and I know it is working, because in Display Options, Theme Function appears under format.

I then have copied the function my theme and changed theme to MYTHEMENAME (see code below). However, the changes do not appear to pick up (I have cleaned the cache):

function MYTHEMENAME_addressfield_address($variables) {

  // Make each sub-field available as its own variable.
  foreach ($variables as $key => $value) {
    $$key = $value;
  }
  
  $output = '';
  // Render street block
  if ($thoroughfare || $premise) {
    $output .= '<div class="street-block customclass1">';
    if ($thoroughfare) {
      $output .= '<div class="thoroughfare customclass2">' . $thoroughfare . '</div>';
    }
    if ($premise) {
      $output .= '<div class="premise customclass3">' . $premise . '</div>';
    }
    $output .= '</div>';
  }
  
  // Render locality block
  if ($locality || $administrative_area || $postal_code) {
    $output .= '<div class="locality-block customclass4">';
    if ($locality) {
      $output .= '<span class="locality">' . $locality . '</span>';
    }
    if ($locality && $administrative_area) {
      $output .= ', ';
    }
    if ($administrative_area) {
      $output .= ' <span class="state stage customclass1">' . $administrative_area . '</span>';
    }
    if ($postal_code) {
      $output .= ' <span class="postal-code customclass1">' . $postal_code . '</span>';
    }
    $output .= '</div>';
  }
  
  return $output;
}

les lim’s picture

@big_smile: make sure you've got the field display set to "Theme function" in the entity's "Manage display" settings. While you're there, check to see that you're setting it for the right display mode - it's easy to set it only for "Default" without realizing that you might have "Teaser" and "Full mode" display modes overriding that.

big_smile’s picture

@Les Lim, I've checked very carefully, it still doesn't work.
Is MYTHEMENAME_addressfield_address($variables) the correct function use?

Thanks for any help that can be offered.

acbramley’s picture

Wow this is just what I was looking for, I'm rendering the address into a CSV and the functions and markup that the default formatter was ouputting just weren't working. I then went to happily override this output as I usually would and couldn't believe how complex this is implemented. This patch provides a great way for not only overriding the default funcitonality, but also programmatic rendering of the address.

acbramley’s picture

Ok, I had a bit of trouble with overriding the theme function but I got there in the end. I went through the following things that didn't work before coming to my solution:

1) Tried using MYTHEME_addressfield_address in the template.php file of my front-end theme. This didn't work as I need it in the admin theme as well.
2) Tried using MYMODULE_addressfield_address in MYMODULE.theme.inc this didn't work either
3) Tried using MYMODULE_addressfield_address in MYMODULE.module again...

Finally, I implemented hook_theme_registry_alter() and this worked a charm. BUT there were some issues, I couldn't seem to have my themeing function in a different file (i.e MYMODULE.theme.inc) so this is what I came out with:

/**   
 * Implements hook_theme_registry_alter().                                                                
 */ 
function my_module_theme_registry_alter(&$theme_registry) {
  $theme_registry['addressfield_address']['theme path'] = drupal_get_path('module', 'my_module');
  $theme_registry['addressfield_address']['function'] = 'my_module_addressfield_address';
}

/** 
 * Theme function for rendering an address.
 *
 * Overrides theme function from patch to just render out the values.
 * This is used in our csv.
 *
 * @param $variables
 *   An array containing the addressfield sub-fields.
 */
function my_module_addressfield_address($variables) {
  // Make each sub-field available as its own variable.
  foreach ($variables as $key => $value) {
    $$key = $value;
  }

  $output = '';
  // Render street block
  if ($thoroughfare || $premise) {
    $output .= $thoroughfare . ' ' . $premise;
  }

  // Render locality block
  if ($locality || $postal_code) {
    $output .= $locality . ' ' . $postal_code;
  } 
  
  return $output;
} 

All done in my_module.module

Hope this helps others.

criz’s picture

Priority: Normal » Major
Status: Reviewed & tested by the community » Needs work

This patch works for me but misses some variables in the default output (like city or organisation).

Anyway, having such a theme function is crucial, as the generated html by addressfield module is complex and hard to work with. For example I had a lot of troubles in commerce order notification e-mails using this module for shipping and invoice addresses. Also one of my clients had some issues copying the addresses from commerce backend to texteditors, because of the generated html.

To sum it up: Being able to adopt the html easily using a theme function would be very important.

rudiedirkx’s picture

You could write

// Make each sub-field available as its own variable.
foreach ($variables as $key => $value) {
  $$key = $value;
}

as

// Make each sub-field available as its own variable.
extract($variables);

and

  • the variables in the theme functions aren't html encoded
  • the line with the default variables is way too long (coding standards say max 80 chars)
  • the theme function (and its preprocessor) doesn't know anything about the field & instance & entity it's rendering

All fixed in new patch attached.

I've also added a formatter setting (subformatter) so you can choose a formatting method you can then use in your custom theme functiion. WIth that, you can more easily specify your theme function, for instance:

<?php
function YOURTHEME_addressfield_address($vars) {
  $subformatter = $vars['display']['settings']['subformatter'];

  if ($subformatter == 'city') {
    return ' ' . check_plain($vars['locality']);
  }

  return theme_addressfield_address($vars);
}
?>

@criz ALL variables are sent to the theme function, the way they're named in addressfield. You're looking for locality (city) and organisation_name. You can see all availables in addressfield_theme().

rudiedirkx’s picture

Status: Needs work » Needs review
criz’s picture

Issue summary: View changes

Had to apply this patch again after update to latest kickstart 7.x-2.13. This is just a notice that the patch from #19 works for me using addressfield 7.x-1.0-beta5.

giorgosk’s picture

I think https://drupal.org/project/addressfield_tokens
solves most theme requirements out of the box
you should try it

but if not it has already implemented some theme functions for more custom solutions

rudiedirkx’s picture

I can't make with addressfield_tokens what #19 makes out of the box. I expected tokens in a field formatter, but there's nothing there...

This really needs to get in.

jenlampton’s picture

Status: Needs review » Reviewed & tested by the community

Looks like @criz meant to mark this one RTBC in #21.

gaëlg’s picture

I can confirm it works well.

monstrfolk’s picture

Updated patch to include country.

Added long country and administrative_area names.

Administrative_area long name only available if country is stored.

monstrfolk’s picture

StatusFileSize
new6.2 KB

In some cases addressfield.administrative_areas.inc does not load. Had to include once.

monstrfolk’s picture

StatusFileSize
new6.2 KB

Fixes Notice: Undefined variable: postal in theme_addressfield_address() (line 367 of /sites/all/modules/addressfield/addressfield.module).