It would be nice if there was a way to alter/override token values.

For example, Ubercart defines an [order_id] token, and sets the value to whatever the order_id is. But I want to replace the value of this token with a prefixed order_id, so anything including the [order_id] token would show the prefixed order_id.

As it stands now you can't just do your own implementation of hook_token_values and set your own value. The $values arrays returned from the hook_token_values functions are merged using array_merge_recursive, so instead of the newer value overwriting the old, you end up with an array containing both values. Because token just does a str_replace with the $tokens and $values arrays, when the token replacement is done you end up with "[order_id]" being replaced with "Array", which is really not helpful.

One idea is to create a "token_prepare_values" function and in the _token_replace_tokens function run the $values array through that before doing the str_replace. The token_prepare_values function would run through the values array and for any value that is an array it would replace that value with the last element in the array.

The function might look something like this:

function token_prepare_values(&$values) {
  for ($i = 0; $i < count($values); $i++) {
    if (is_array($values[$i])) {
      $values[$i] = end($values[$i]);
    }
  }
  return $values;
}

And the altered _token_replace_tokens function would look like this:

function _token_replace_tokens($original, $tokens, $values, $leading, $trailing) {
  $tokens = token_prepare_tokens($tokens, $leading, $trailing);
  $values = token_prepare_values($values);
  return str_replace($tokens, $values, $original);
}

If this can't be done for some reason, maybe there could be a hook_token_value_alter() or something like that, but this seems like a pretty simple way to make it work.

Thanks. :)

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Dave Reid’s picture

Status: Active » Postponed

I'm not sure if this would be possible. Token is already in core and feature locked without any kind of alter hook, so I don't think it would make much sense to add that feature here, just to have it removed in Drupal 7. :/

Maybe just leave this postponed for now?

adamo’s picture

OK. Would be a nice feature to have. ;)

TonyK’s picture

Status: Postponed » Active

+1 to hook_token_value_alter(). This would be a great feature. Why would inclusion of this module into the core of the next Drupal version affect 6.x version of contributed module? IMO the decision to move several modules to the core is rather questionable because it obviously suppresses Drupal development. :(

Dave Reid’s picture

Status: Active » Closed (won't fix)

Because if we added a new api in the module for D6 but it's not supported in D7, it wouldn't make sense to do since we'd lose functionality.

Damien Tournoud’s picture

Project: Token » Drupal core
Version: 6.x-1.x-dev » 7.x-dev
Component: Code » base system
Status: Closed (won't fix) » Active

This is brain-dead. We definitely need an alter hook here.

Dave Reid’s picture

This is possible in D7. Just ensure your module runs after (module weights)? Or do we need an explicit alter hook?

Damien Tournoud’s picture

No, this not possible neither on D6 nor on D7. For the same reason: if two implementations return the same key, we end-up with an array (see #791860: array_merge_recursive() is never what we want in Drupal: add a drupal_array_merge_recursive() function instead.).

Dave Reid’s picture

I just committed a patch to token module to prevent this in D6 so yes, it is very possible: #587148: Handle tokens correctly when more than one module defines a given token. I do see we have a problem in D7 though and it should be a proper alter hook.

Damien Tournoud’s picture

Status: Active » Needs review
FileSize
2.65 KB

Something like this?

This is an untested patch.

Dave Reid’s picture

Component: base system » token system

Will review this week, although looking good.

ohnobinki’s picture

.

Dave Reid’s picture

I like it, although the docs between hook_tokens and hook_tokens_alter should probably add @see lines to each other.

Dave Reid’s picture

Assigned: Unassigned » Dave Reid
Category: feature » task

Assigning myself to re-roll tomorrow.

Dave Reid’s picture

Re-rolled with additional linking @see comments and small move in system.api.php to keep all the token api functions together.

Dave Reid’s picture

Issue tags: +token

Adding tag...

Dave Reid’s picture

DamZ? Look good?

Damien Tournoud’s picture

Status: Needs review » Reviewed & tested by the community

Yep, looks really good to me.

Dave Reid’s picture

Another reasoning for this patch will easily allow any tokens to be translated via a i18n_tokens_alter(). Currenly the token_replace() function only allows one $options['callback'] function, so if tokens that want to translate pathauto tokens do not get a chance since pathauto claims the callback function.

Dries’s picture

Version: 7.x-dev » 8.x-dev

I think this waits for Drupal 8.

Dave Reid’s picture

Status: Reviewed & tested by the community » Needs review

Fair enough, I'd like to make a case for this to go into 7.1 since there is no way for this to happen in contrib. I will bump this down to needs review for now.

Dave Reid’s picture

Issue tags: +API addition

Adding tags...

Damien Tournoud’s picture

Version: 8.x-dev » 7.x-dev
Category: task » feature
Status: Needs review » Reviewed & tested by the community

This is a major regression from D6, and a very minor API addition.

Please reconsider.

Dave Reid’s picture

I would point out that it's actually not a regression. We don't have an hook_token_values_alter() in the Token module/API for D6 at all...

Damien Tournoud’s picture

True, but in recent version it's at least possible for a higher-weight module to modify the tokens exposed by lower-weight modules... and that turned out to be *pretty useful* in a few recent projects of mine.

Dave Reid’s picture

Gah, I just came across a couple use cases in contrib for this. For example, we provide a [current-page:title] token in Token.module. The Page Titles module should be able to alter that token rather than having to provide its own.

Dries’s picture

Status: Reviewed & tested by the community » Fixed

Well, I decided to commit this. It is a minor change and had been RTBC for a long time. And I trust Dave's judgment that it is important for contrib.

Dave Reid’s picture

Status: Fixed » Needs work

I had just noticed this yesterday but I forgot to include hook_tokens_alter() in system_hook_info() so that the hooks can be included in modulename.tokens.inc just like the rest of the token functions.

Dave Reid’s picture

Dave Reid’s picture

Status: Needs work » Needs review
moshe weitzman’s picture

Status: Needs review » Reviewed & tested by the community

makes sense

webchick’s picture

Status: Reviewed & tested by the community » Fixed

Committed to HEAD, minus the coding standards changes. If we want to do that (I'd argue that we don't) it can be a separate follow-up issue that changes it both here and in the API docs for consistency.

Dave Reid’s picture

Sounds good Angie, leaving the coding style is fine with me.

jhedstrom’s picture

Now that this has been fixed in 7, any chance of a back-port to the 6.x token module?

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

TonyK’s picture

Just a note: Drupal 6 backport is discussed here: #1157058: Add hook_token_values_alter() to allow altering of tokens.