Drupal intra-linking problems solved

Updated: Thu, Feb 11, 2010 - 3:37pm
Type
Status
Concerning

Sometimes, when using Drupal, I find that I want to link to some of my older posts. However, I often have a couple of development checkouts of my site. Consider the case where I have the live site, which can be reached at http://iheartryan.com/, and I have a development checkout, http://localhost/iheartryan/. Now, say I'm trying to link to my Rhythmbox Playlist Folders post. How should I make this link? I have a couple choices:

  1. http://iheartryan.com/post/rhythmbox-playlist-folders
  2. /post/rhythmbox-playlist-folders

Neither of these will totally work for my purposes. For example, let's say I choose to make a full, absolute path, like #1 above, then when I look at this page in my development checkout, the link will point to the post on the live server. I can't navigate around internally on my dev checkout.

Choice #2 might help with that problem. It is a link to the post on whatever server I happen to be looking at. The problem is that my dev checkout has a different path. So choice #2 will give us a link to: http://localhost/post/rhythmbox-playlist-folders. What we need is a link to http://localhost/iheartryan/post/rhythmbox-playlist-folders.

I have a solution that will cover most of the cases. If you implement this solution on your site, then you can just make a link to /post/rhythmbox-playlist-folders, and it will be translated to /post/rhythmbox-playlist-folders, so it will work on any checkout.

To implement this solution, we will make some changes in a module and some changes in your site's theme.

First, the module. We need to have a module that implements hook_nodeapi. For all the sites I do, I always end up with some custom modifications, so let's say we have a module called "custom". (Technically, I could take the changes I'm about to present and release it as a module, but it is incomplete without the theme changes, and it doesn't seem like it should be a whole module release). In our custom module, I will implement hook_nodeapi:

  1. function custom_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
  2. switch($op) {
  3. case 'view':
  4. $node->content['body']['#value'] = preg_replace_callback(
  5. '/<([^>]*)(src|href)="([^"]*)"/i',
  6. "_custom_twiddle_links",
  7. $node->content['body']['#value']);
  8.  
  9. break;
  10. }
  11. }
  12.  
  13. function _custom_twiddle_links($matches) {
  14. $url = $matches[3];
  15. if (preg_match('|^[a-z][^:]*://|', $url)) {
  16. // It's an absolute url. Return the whole thing as given.
  17. $retval = $matches[0];
  18. } elseif (strpos($url, "/") === 0) {
  19. // It's an absolute url on this host. Fix it with the right base path.
  20. $retval = "<{$matches[1]}{$matches[2]}=\"".base_path().ltrim($matches[3],"/")."\"";
  21. } else {
  22. // It's a relative url. Return the whole thing as given.
  23. $retval = $matches[0];
  24. }
  25.  
  26. return $retval;
  27. }

This will replace the links when displaying nodes.

There's still the problem of blocks. That's why we edit the site's theme.

We edit blocks.tpl.php to start with this:

  1. <?php
  2. /**
  3.  * If a link starts with /, it should be relative to the base_path of the site,
  4.  * not to the actual server root.
  5.  */
  6. if (!function_exists("_block_twiddle_links")) {
  7. function _block_twiddle_links($matches) {
  8. $url = $matches[3];
  9. if (preg_match('|^[a-z][^:]*://|', $url)) {
  10. // It's an absolute url. Return the whole thing as given.
  11. $retval = $matches[0];
  12. } elseif (strpos($url, "/") === 0) {
  13. // It's an absolute url on this host. Fix it with the right base path.
  14. $retval = "<{$matches[1]}{$matches[2]}=\"".base_path().ltrim($matches[3],"/")."\"";
  15. } else {
  16. // It's a relative url. Return the whole thing as given.
  17. $retval = $matches[0];
  18. }
  19.  
  20. return $retval;
  21. }
  22. }
  23.  
  24. if ($block->module == 'block') {
  25. $block->content = preg_replace_callback(
  26. '/<([^>]*)(src|href)="([^"]*)"/i',
  27. "_block_twiddle_links",
  28. $block->content);
  29. }
  30. ?>

This will fix the links for blocks.

That's the best I can do. This solution is not elegant. Perhaps there can be a a fix at the Drupal core level, so that we won't have to apply these dirty hacks. Perhaps this hack could be adjusted to have a token like [BASE_PATH], instead of working on all server-absolute links.

Perhaps there could even be a solution using the existing token module. Please tell me if you know of one.

Your rating: None Average: 3.5 (8 votes)

Reply

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>. Beside the tag style "<foo>" it is also possible to use "[foo]".

More information about formatting options

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
  _              _               _   _    
| |__ __ __ | |__ __ _ (_) | | __
| '_ \ \ \/ / | '_ \ / _` | | | | |/ /
| |_) | > < | | | | | (_| | | | | <
|_.__/ /_/\_\ |_| |_| \__, | |_| |_|\_\
|_|
Enter the code depicted in ASCII art style.