_relatedlinks_filter(): Not quite right

kingandy - July 2, 2009 - 12:26
Project:Related links
Version:5.x-2.2-beta
Component:Code
Category:bug report
Priority:normal
Assigned:Unassigned
Status:active
Description

The code that generates the actual link for relatedlinks blocks reads as follows:

<?php
$urls
[] = '<a href="'. check_url($link['url']) .'">'. check_plain($link['title']) .'</a>';
?>

I can see why it uses check_url() instead of, say, url() or l(); the URL has to be derived from a single line and therefore may contain a query string, making it unsuitable for processing by those functions (which take query string as a separate parameter). Unfortunately this is a source of fail for manual links on a site that uses clean URLs, since it does not prepend base_path() - if your page has a url of 'node/1' and has a relatedlink of 'node/2' set, clicking on the link will take you to 'node/node/2'. It's interpreted as a relative link instead of absolute. (Also this doesn't use any path aliases that don't exist, though I'm aware this is listed as a "To Do" for the function.)

I think ideally we'd need to parse the URL at this stage and break it into path / query, and then run it through url() or l()[1] to get the fully-qualified, base_path() prepended, clean-or-not-clean path for proper internal/external use.

Unfortunately, I don't know (or have the time to work out) how to do that, so I've slapped together a quick fix for my own use. It's very rudimentary and does assume that you're using clean URLs but might be a starting point for somebody. It also includes some switching for external links (http://, https://) and tries to fetch an alias if appropriate. Finally I added another $url_cache line, so that both the aliased and un-aliased URLs get cached. I don't imagine a massive performance hit if the same URL gets cached twice, but I'd welcome suggestions regarding better ways of doing this.

<?php
function _relatedlinks_filter($links) {
 
$urls = array();
 
$url_cache = array();

  foreach (
$links as $link) {
    if (!
in_array($link['url'], $url_cache)) {
     
// Added this $url_cache line:
     
$url_cache[] = $link['url'];
      if (empty(
$link['title'])) {
       
// URLs without a title display the URL.
       
$link['title'] = $link['url'];
      }
     
// Added this IF clause:
     
if (strpos($link['url'], 'http://') !== 0 && strpos($link['url'], 'https://') !== 0) {
       
$link['url'] = drupal_get_path_alias($link['url']); // returns original path if path not found
       
if (strpos($link['url'], '/') !== 0) {
         
$link['url'] = base_path() . $link['url'];
        }
      }
     
// End of added code
     
$url_cache[] = $link['url'];
     
$urls[] = '<a href="'. check_url($link['url']) .'">'. check_plain($link['title']) .'</a>';
    }
  }
  return
$urls;
}
?>

[1] ... Actually, what we really need to do is remove this HTML formatting from the _filter function, and shift it into the theme_relatedlinks function. But that would be a pretty fundamental shift in the way theme_relatedlinks works, rather than a straightforward fix to already existing functionality, so maybe that's outside the scope of this issue.

#1

kingandy - July 2, 2009 - 12:31

Oh hey I guess I already came up against this last year - #313663: Bug when used with pathauto. FWIW, now I've thought about why clean_url is being used I kind of disagree with the change made in that patch.

 
 

Drupal is a registered trademark of Dries Buytaert.