Drupal intra-linking problems solved
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:
- http://iheartryan.com/post/rhythmbox-playlist-folders
- /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
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:
function custom_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) { switch($op) { case 'view': '/<([^>]*)(src|href)="([^"]*)"/i', "_custom_twiddle_links", $node->content['body']['#value']); break; } } function _custom_twiddle_links($matches) { $url = $matches[3]; // It's an absolute url. Return the whole thing as given. $retval = $matches[0]; // It's an absolute url on this host. Fix it with the right base path. } else { // It's a relative url. Return the whole thing as given. $retval = $matches[0]; } return $retval; }
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:
<?php /** * If a link starts with /, it should be relative to the base_path of the site, * not to the actual server root. */ function _block_twiddle_links($matches) { $url = $matches[3]; // It's an absolute url. Return the whole thing as given. $retval = $matches[0]; // It's an absolute url on this host. Fix it with the right base path. } else { // It's a relative url. Return the whole thing as given. $retval = $matches[0]; } return $retval; } } if ($block->module == 'block') { '/<([^>]*)(src|href)="([^"]*)"/i', "_block_twiddle_links", $block->content); } ?>
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.