When I use a custom token for taxonomy 'needs term' I get the following errors from pathauto:

Warning: Illegal offset type in isset or empty in pathauto_cleanstring() (line 180 of /var/www/wet/profiles/wetkit/modules/contrib/pathauto/pathauto.inc).
    Warning: html_entity_decode() expects parameter 1 to be string, array given in decode_entities() (line 429 of /var/www/wet/includes/unicode.inc).
    Warning: Illegal offset type in pathauto_cleanstring() (line 223 of /var/www/wet/profiles/wetkit/modules/contrib/pathauto/pathauto.inc).

I have been able to recreate this issue with a minimal set of modules and the following test case:

1. Define a custom token simply called "Testing" of type 'term' which prints the text 'testing'.
2. Create a test vocabulary with one term
3. In pathauto define a pattern for the vocabulary which is [term:testing]/[term:name]
4. Now edit your term and the error message should appear

To recreate the error messages programatically, you can run the following in devel/php:

$op = 'return';
module_load_include('inc', 'pathauto');
$term = taxonomy_term_load(1);
$uri['path'] = 'taxonomy/term/1';
$pathalias = pathauto_create_alias('taxonomy_term', $op, $uri['path'], array('taxonomy_term' => $term), $term->vocabulary_machine_name, 'en');

One thing I noticed is that hook_tokens in token_custom gets run twice, once with $options['recursive'] = TRUE and another time without. If I add the following to token_custom.module the error goes away and everything still seems to work:

175   if (isset($options['recursive'])) {
176     return $return;
177   }

I don't think this is the real fix, but I thought it may help debug the issue further.

Comments

joel_osc’s picture

Title: Pathauyto cleanstring errors on taxonomy term tokens » Pathauto cleanstring errors on taxonomy term tokens

Fixed title.

gaspaio’s picture

This seems to me a Token module issue causing the custom token to be resolved twice, its value becoming an array in the process and causing the errors.
I opened an issue in the Token issue queue (#1792728: token_tokens() returns token replacements managed by other modules) for this.

In the meantime, you can probably achieve the same result if you use some other non-entity token type for your custom token, like site information for example, or a custom type with no entity dependencies;

Dave Reid’s picture

I think the problem here is the following:

Define a custom token simply called "Testing" of type 'term' which prints the text 'testing'.

This token should not return anything if $data['term'] is empty. Does this actually happen?

gaspaio’s picture

When the token value is given by :
return !empty($data['term']) ? "testing" : NULL;
the error is still there.

I think this is because, as i indicated in #1792728: token_tokens() returns token replacements managed by other modules, the same custom token is resolved twice.

joel_osc’s picture

Please keep in mind that the use of 'Testing' was simply to create the most basic of test cases. In my actual configuration I am using a php_field and doing operations on $data to return my token. I just wanted to remove some variables from the equation while troubleshooting to provide the simplest situation under which the problem will occur. Thanks!

Dave Reid’s picture

What kind of operations are you performing on $data?

joel_osc’s picture

Hmm, maybe my grammar threw things off here - I meant to say with $data. Just returning the tid out of it will generate the same error or simply return "testing" with no other php code. I was just trying to clarify that not using "needs term" was not a viable workaround. Thx.

mahmost’s picture

Something goes wrong with 'term' tokens .. even with gaspaio's code in #4 it passes each token in $replacements as an array $replacements = array("[term:token-name]"=>array("good data","");to the $options['callback'] instead of $replacements = array("[term:token-name]"=>"good data");

This seems to result from an extra call of module_invoke_all('tokens',...) in token.tokens.inc (which is referenced in this patch #1792728: token_tokens() returns token replacements managed by other modules, bypassing this call makes things work for this specific case.

the edit in the issue summary also fixes the bug for my use case.

jeremylichtman’s picture

The simplest fix is likely in pathauto_clean_token_values (approximately line 605 in pathauto.inc).

i.e. inside the foreach loop, before the preg_match, add this:

if(is_array($value)) {
$value = array_shift($value);
}

This allows pathauto to work with custom tokens, without attempting to resolve the larger issue with tokens.

Cracu’s picture

I got into same problem, by updating location module to 7.x-3.3 which contains a line similar to:

$replacements[$original] = (isset($node->{$field}[LANGUAGE_NONE][$position][$item]) ? $node->{$field}[LANGUAGE_NONE][$position][$item] : '');
in location_cck_tokens function.

I think some modules are doing it wrong, by setting empty value for token. I ended up with an array similar to:

array('', '<actual_value')

I've fixed temporary by adding an if right before:

if (isset($node->{$field}[LANGUAGE_NONE][$position][$item])) {
   $replacements[$original] = $node->{$field}[LANGUAGE_NONE][$position][$item];
}
1kenthomas’s picture

Hmm. #9 and #10 are both rather blunt solutions which involve patching external modules (it's not clear to me whether the patches to these modules have merit, that is, are a better way to solve than a change to this module).

Is is possible to move towards a solution that has the potential of being committed / won't require patch management?

Thanks, best, Ken