How is it possible to use token replacement for a text_formatted data type?

I tried to implement hook_rules_evaluator_info_alter() and add text_formatted to the supported types, but that won't solve the problem because token_scan() expects a string.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

sgabe’s picture

Title: Token replacement for text_formatted data type » Token replacement and PHP evaluation for text_formatted data type

It seems the PHP evaluation also not works for text_formatted data type. I would like to know if there is a solution or these features are only available for text data type.

Changing title to better reflect the problem.

fago’s picture

Category: support » task

Indeed, for that to work we need to special case the replacement code to replace tokens in $data_value['value].

sgabe’s picture

The same applies to the PHP evaluation? (It needs to be and will be solved in Rules?)

butler360’s picture

Subscribing.

Edit: Just noticed the new "Follow" button. Oops.

mitchell’s picture

Component: Provided Rules integration » Rules Core

Updated component.

sgabe’s picture

Torenware’s picture

Would you folks allow a patch on this?

I've spent some time wandering through the token processing code in rules; it may not be that hard to do this.

willieseabrook’s picture

Not sure if this is the right issue to place this, but #1667482: Send a text field value as an HTML mail via Rules is marked as a duplicate of this, and it's similar to my problem.

I have two fields:

1. Message::args!myargument
2. Message:emailbody

I'm trying to take emailbody, which is an HTML field with a "Full HTML" filter and use it to set the value of the argument !myargument, which is also a field with a "Full HTML" filter.

This doesn't work - the HTML in emailbody is stripped during the set action. I've found where it occures:

function rules_unwrap_data(array $data, $info = array()) {
  $cache = rules_get_cache();
  foreach ($data as $key => $entry) {
    // If it's a wrapper, unwrap unless specified otherwise.
    if ($entry instanceof EntityMetadataWrapper) {
      if (!isset($info[$key]['allow null'])) {
        $info[$key]['allow null'] = FALSE;
      }
      if (!isset($info[$key]['wrapped'])) {
        // By default, do not unwrap special data types that are always wrapped.
        $info[$key]['wrapped'] = (isset($info[$key]['type']) && is_string($info[$key]['type']) && !empty($cache['data_info'][$info[$key]['type']]['is wrapped']));
      }
      // Activate the decode option by default if 'sanitize' is not enabled, so
      // any text is either sanitized or decoded.
      // @see EntityMetadataWrapper::value()
      $options = $info[$key] + array('decode' => empty($info[$key]['sanitize']));

      try {
        if (!($info[$key]['allow null'] && $info[$key]['wrapped'])) {
          $value = $entry->value($options);

The key is the line "$value = $entry->value($options);"

This is where $value, which used to be HTML, comes out plain text.

We see two lines basically saying HTML is banned:

      // Activate the decode option by default if 'sanitize' is not enabled, so
      // any text is either sanitized or decoded.

Why?

$entry is of type EntityValueWrapper, so we look deeper:

class EntityValueWrapper extends EntityMetadataWrapper {

  /**
   * Overrides EntityMetadataWrapper#value().
   * Sanitizes or decode textual data if necessary.
   */
  public function value(array $options = array()) {
    $data = parent::value();
    if ($this->type == 'text' && isset($data)) {
      $info = $this->info + array('sanitized' => FALSE, 'sanitize' => 'check_plain');
      $options += array('sanitize' => FALSE, 'decode' => FALSE);
      if ($options['sanitize'] && !$info['sanitized']) {
        return call_user_func($info['sanitize'], $data);
      }
      elseif ($options['decode'] && $info['sanitized']) {
        return decode_entities(strip_tags($data));
      }
    }
    return $data;
  }
}

Particularly:

      if ($options['sanitize'] && !$info['sanitized']) {
        return call_user_func($info['sanitize'], $data);
      }
      elseif ($options['decode'] && $info['sanitized']) {
        return decode_entities(strip_tags($data));
      }

We can see that I'm either allowed check_plain or strip_tags, but certainly not HTML.

What to do? I need to be able to set an HTML field, and I can't figure out what hook to use. I don't see anywhere where I can override the use of EntityValueWrapper for just my field and make a GiveMeHTMLEntityValueWrapper class.

Nor does the logic appear to allow me to change $options.

So, how do I set/get an HTML field without nuking the HTML? Again, apologies if this is the wrong issue, but the duplicate did appear to be very similar.

willieseabrook’s picture

willieseabrook’s picture

For now, I've used the following hack. So I can continue dev until I figure this out more.


      // Activate the decode option by default if 'sanitize' is not enabled, so
      // any text is either sanitized or decoded.
      // @see EntityMetadataWrapper::value()
      $options = $info[$key] + array('decode' => empty($info[$key]['sanitize']));

      // Override the HTML stripping of rules.
      // See #1304682: Token replacement and PHP evaluation for text_formatted data type
      if ($key == 'value') {
        $options['decode'] = FALSE;
        $options['sanitize'] = TRUE;
        $options['sanitized'] = TRUE;
      }

smokris’s picture

Here's an attempt to add token support for text_formatted.

(I've also attached an extra patch that applies to 7.x-2.2.)

Status: Needs review » Needs work

The last submitted patch, rules-text-formatted-tokens-1304682-11.patch, failed testing.

KimmoT’s picture

Issue summary: View changes

I have another temporary solution for this. I used plaintext for creating the html with replaced tokens and used a custom action for passing the values as formatted text:

function mymodule_rules_action_info(){
	$actions = array();
	$actions['mymodule_pass_plain_to_formatted'] = array(
		'label' => t('Pass plain text to formatted'),
		'parameter' => array(
	      'text' => array(
	        'type' => 'text',
	        'label' => t('Plain text'),
	        'save' => TRUE,
	      ),
	    ),
	    'group' => 'mymodule',
	     'provides' => array(
	      'formatted_val' => array(
	        'type' => 'text_formatted',
	        'label' => t('Formatted value'),
	      ),
	    ),
	);
	return $actions;
}


function mymodule_pass_plain_to_formatted($plain){	
	$out = html_entity_decode($plain);
	$arr = array(
		'value' => $out, 				
		'format' => 2 //full_html
	);
	$output = array(
		'formatted_val' => $arr
	);
  	return $output;
}
kopeboy’s picture

Updates?

I am here because I would like to send a rendered entity in an email with Rules.
I am using Mandrill, and already sending HTML emails, the problem is Rules won't let me select the entity and view mode but only text fields of the entity in the email body.

Arjandew’s picture

hmm the php replacement work as expected.
But the normal token replacement is not working in rules.

got it working to use the following replacement

<?php
$variable['value'];

?>

Now i can use formatted_text variable in rules :)

delacosta456’s picture

@KimmoT

In rules After creating the using plaintext to creating the html wit replaced token ... you can add one more action of "Set data value" of the (your)text_formated field by making that you choose like below

node:field-(your)text_formated:format Please notice the "format" at the end.