When a heartbeat message is displayed regarding the creation of a node, the node link is displayed using the system alias (node/847) rather than the alias (page/path)

This is not a major issue as it works fine, but I think it's a little messy as the URLs are not consistant. Thankfully, Global Redirect is making sure this does not harm the search engine results with duplicate content, but some developers may not be so lucky.

Comments

Stalski’s picture

Status: Active » Closed (fixed)

This is a known problem. When using the rules module and logging activity with it, it's not possible to create path aliased urls as this process has not been done yet.
I do my loggings by calling the heartbeat_api_log function (see example module). This way you choose where you log (... after the tokenization that is).

So this is one that i cannot fix.

darklight’s picture

Okay. Thanks for replying. :)

mstef’s picture

Version: 6.x-4.5 » 6.x-4.10
Status: Closed (fixed) » Active

I think this may have reopened.. it seems that way

Stalski’s picture

what do you mean? This is not something heartbeat can solve imho

mstef’s picture

I updated to 4.10.. and now i'm seeing newly created activity items link to /node/123 instead of blog/the-title-of-my-blog (pathauto setting)..

Heartbeat doesn't output links with l()?

Stalski’s picture

Heartbeat does use that in the tokens values, so they can be used in rules. So it's a bit out of my hands.
I did not change anything for that, even worse, i don't understand you ever had it working. Since the start i always had node/123 on creation.

Stalski’s picture

to be sure, i asked Fago on IRC and he said pretty much the same thing:
(05:16:07 PM) fago: Stalski, I see. of course, if the alias is not saved yet, it won't be applied. Nothing rules can do about...

mstef’s picture

I'm getting a mix of aliases and paths

Stalski’s picture

yes sometimes it works. I don't know how i could make sure the path is already created. It seems dangerous to in token values trying to create a path alias. It's not really the job of heartbeat ofcourse.
Do you have any idea's?

mstef’s picture

If the nid is stored, just output l($title, "node/$nid") or whatever - l() does the rest

I also noticed that (i'm not 100% certain yet) but devel generated content produces activity messages that definitely don't go through l() because the bath_path was incorrect (my site is currently site.com/drupal - it was doing site.com/node/1 instead of site.com/drupal/node/1)

Stalski’s picture

Status: Active » Closed (won't fix)

If the nid is stored, just output l($title, "node/$nid") or whatever - l() does the rest

Can i remind you of the fact that links are logged in heartbeate_activity message as cached field. Only when using the rules module, the pathauto did not get the chance yet to create a path for the node, so in the heartbeat message, it replaces the patterns in the message template with what it has returned from the l() function at that time. At that point, it is still node/NID.

Nothing i can do to change that. so again, it already goes through the l function ofcourse.

Sollutions:
- Log to heartbeat activity in the nodeapi for instance. No problems there.
See example module : http://drupalcode.org/viewvc/drupal/contributions/modules/heartbeat/modu...
- Implement heartbeat_messages_alter and loop through $messages.
$message->message = $message->rebuild_message();

I will close this one as it is not the responsibility of heartbeat in the first place. Node path auto just comes later than the execution of the rules action.

Daedalon’s picture

Version: 6.x-4.10 » 7.x-1.0
Status: Closed (won't fix) » Active

I'd like to report that this is still an issue with Heartbeat 7.x-1.0 and Rules 7.x-2.0. A quick search didn't provide a workaround or an issue at the Rules queue to participate in. Is there a known workaround to implement? If not, which is the appropriate place to participate in solving this?

Stalski’s picture

The only way I can think of, is at runtime (when streams are displayed). For this matter you could do this in heartbeat_theme_alter.

For this to make sense, we need to replace the variables that are links into new links. So we need some information on how to do this. The solution here is still hardcoded in the way that we need to know it's a node link and we can recreate a link to the node if we have the nid as nid or nid_target variable...

Do you understand what I mean by this? Maybe I'll post an example this week...

Daedalon’s picture

If I understood correctly, Heartbeat calls l() to format the link when the activity occurs, and then saves it to database. What I don't understand is why this doesn't catch the alias when updating a node. If I've understood the workings of l() correctly, then as the alias already exists it should be returned by l() in heartbeat/modules/heartbeat_rules.module:

    foreach ($tokens as $name => $original) {
      switch ($name) {

        case 'link':
          $replacements[$original] = l($node->title, 'node/' . $node->nid, $url_options);
          break;
      }
    }

However, because Pathauto aliasing options can be changed, any hard-coded aliases are prone to become invalid. I believe the only option that lets Heartbeat show URLs like the rest of the site is by formatting them at runtime as Stalski suggests. For performance, the results can be cached. If possible, the event of changing Pathauto aliases or mass deleting / creating them should invalidate the cache.

Thumbs up for runtime URL formatting from here.

Stalski’s picture

Status: Active » Postponed

Well thumbs up here too, but it's so difficult that I won't start development of it.

The reason why l does not find the url alias on node creation is since the pathauto module comes after the rules event is triggered.
Custom activity logging does not have that problem.

So problems:
- when logging activities of new nodes: Pathauto did not create it yet
- when logging activities of changed nodes: Pathauto did not modify it yet

I'll postpone this again as it is too hard. It seems like we need some special object that stores all information that "could" be used in the l-function. So nid is the easiest one, but for nodes we need the title, for users the name, taxonomy it's term name, ...
Another possibility would be to store complete entities (the user logging activity, the node in the activity, the term, etc ...) but as you can expect, this is very hard and performance will go down big time.

Daedalon’s picture

I'm not familiar with Heartbeat's code, so I'm curious about why would formatting in the runtime be hard? Doesn't the same call to l() with the same parameters then give the aliased URL?

Stalski’s picture

I don't link this to "heartbeat code" but to the requirement of the L function. The l-function needs at least a path and a link title. Both require variables that are known in a certain context (a node, a term, whatever, ...)
So to know the link title , we need to know at lease the entity ID (and thus also whether it's a node , the entity type....
This results in the fact that we need lots of scope and context to create links at runtime.

I would be happy if you found a solution and a patch :) . That could speed things up big time

Daedalon’s picture

It's beyond me at this moment how to do it correctly, but in principle I'd think that the only thing needed is to save to database the information currently used to call l() and then have the call to l() happen on runtime based on the information from database. Theoretically this would require changes to only two to four lines of code:

1. Change the current call to l() to save the information instead
2. Change the current displaying of the saved information to call l() based on what is saved
(3.-4.) The counterpart lines of the above that deal with the db.

Not being more familiar with Heartbeat and Drupal module coding I can't say if it would be more challenging than that in practice. The above steps only need to be repeated for each separate and relevant l() call, namely node and user.

Stalski’s picture

The L function needs a path and a link-title ... that's all. But how will you know the "new" link-title?

Daedalon’s picture

As we have the node (or user) id saved, I suggest querying the rest from the database.

Stalski’s picture

So you are up for a patch then? :)
You make it sound so easy.

Daedalon’s picture

I'd gladly do that if I'd have the required skills already - mainly the familiarity with Heartbeat and Drupal modules. At the moment I can study the code superficially to figure what's going on in general, but it will be a long while until my Drupal and Heartbeat knowledge are at the level where I could do these changes without unintentionally introducing a host of new bugs.

vflirt’s picture

Issue summary: View changes

Hi,

i have same problem. What i do not understand is why in function "heartbeat_tokens" in heartbeat_rules.module file you are setting:
1) $url_options = array('absolute' => FALSE);
2) $url_options['alias'] = TRUE;
with this settings the call l($node->title, 'node/' . $node->nid, $url_options) will always return node/... and will never return the alias. Also i am not sure why you need the absolute to be false either.

What i have done is in my custom module implement hook_entity_view_alter for the type 'heartbeat_activity' like this :

if ($type == 'heartbeat_activity') {
    $build['#author'] = user_load($build['#heartbeat_activity']->uid);
    $data = array(
      'author' => $build['#author'],
    );
    if (!empty($build['#heartbeat_activity']->uid_target)) {
      $build['#target_user'] = user_load($build['#heartbeat_activity']->uid_target);
      $data['target_user'] = $build['#target_user'];
    }
    if (!empty($build['#heartbeat_activity']->nid_target)) {
      $build['#target_node'] = node_load($build['#heartbeat_activity']->nid_target);
      $data['target_node'] = $build['#target_node'];
    }
    $message = $build['message']['#markup'];

    $replacements = array();

    foreach (token_scan($message) as $var_name => $tokens) {
      $data_tokens = array();
      if (!empty($data[$var_name])) {
        switch ($var_name) {
          case 'target_node':
            $type = 'node';
            break;
          default:
            $type = 'user';
        }
        $data_tokens[$type] = $data[$var_name];
      }
      $replacements += token_generate($type, $tokens, $data_tokens);
      // Remove tokens if no replacement value is found. As token_replace() does
      // if 'clear' is set.
      $replacements += array_fill_keys($tokens, '');
    }

    // Actually apply the replacements.
    $tokens = array_keys($replacements);
    $values = array_values($replacements);
    $message = str_replace($tokens, $values, $message);

    $build['message']['#markup'] = $message;
  }

I needed tokens for target_node and target_use so this way they are always replaced so i could do something like [target_node:link] token. But as explained above this produces ugly urls with node/123123 that is not good. If i change the way heartbeat_tokens function returns the link token with $url_options['alias'] = FALSE; then all is working as expected.

Kind Regards,
Dobromir

designguru’s picture

A simple solution for anyone still finding this problem is to use the https://www.drupal.org/project/globalredirect module which will automatically redirect visitors to the aliased path.

q./