4

I'm working on a migration from another CMS to WordPress. The old site had terrible SEO-unfriendly URLs in the format http://example.com?lid=1234.

We have imported all the posts from the old site into WordPress and are storing the lid as a custom field.

We would love the old URLs to still work if possible, but as there are about 3,000 posts using .htaccess is out of the question.

So my question is: how would I create a rewrite rule that extracts the lid value from the URL and redirects to the post that contains it in the custom field? (the lid value is unique, so there are no worries about more than one post with the same custom field value)

Many thanks Simon

2 Answers 2

6

here is an idea, first add lid to query_vars:

add_filter('query_vars', 'lid_query_vars');
function lid_query_vars($vars) {
    // add lid to the valid list of variables
    $new_vars = array('lid');
    $vars = $new_vars + $vars;
    return $vars;
}

then use parse_request hook to create your redirect

add_action('parse_request', 'lid_parse_request');
function lid_parse_request($wp) {
    // only process requests with "lid"
    if (array_key_exists('lid', $wp->query_vars) && $wp->query_vars['lid'] != '') {
        $args = array('meta_key' => 'lid', 'meta_value' => $wp->query_vars['lid']);
        $redirect_to_post = get_posts($args);
        foreach($redirect_to_post as $p){
            $link = get_permalink($p->ID);
            wp_redirect( $link , 301 ); 
            exit;
        }
    }
}
2
  • 1
    thanks very much, that does the job perfectly. one question: do i need to clean data coming out of query_vars or has that been done by WordPress already? (i.e. if i was using $_GET['lid'] i would put it through absint before using it) Commented Mar 23, 2011 at 16:20
  • Thanks a million. I had a different requirement, but the query_vars filter was just what I needed.
    – Hobo
    Commented Apr 5, 2011 at 7:34
5

Hi @Simon Blackbourn:

While I was writing my answer but before I could post it @Bainternet jumped in with a great answer too. He took a slightly different approach but his works equally as well as mine. Still, since I'd already written mine when I saw his I'll submit mine as an alternate for you to consider.

Uses Direct SQL: $post_id = $wpdb->get_var($sql)

My solution uses direct SQL which is often not the best approach but I feel it is fair here because of this SQL's simplicity (and is thus unlikely to break in the future) and because for your needs there is no benefit to using the comparatively heavy get_posts() with all its need to process hooks since your needs are one-off for your specific site.

Uses Direct URL Parameters: $_GET['lid']

Additionally I chose to use direct access to $_GET['lid'] instead of first creating a query_var because query vars are part of the standard WordPress query architecture that is use by the underlying URL rewrite system, and for your use-case you are explicitly not leveraging the WordPress query architecture. Instead you need to capture an actual query parameter passed on the URL so I think there isn't really a need for the overhead of adding a query var (although truth be told using a query var doesn't hurt, and it works fine too.)

Uses the 'parse_request' Hook

Lastly I did like @Bainternet use of 'parse_request' hook; it runs before WordPress' default MySQL query, so you don't have to run a MySQL query you will just throw away yet it runs after the 'init' hook which means (most) hooks that allow plugins to modify permalinks will have been added thus giving you the correct URLs for your redirects.

Place in functions.php

You can place the following code into your theme's functions.php file:

add_action('parse_request','oldsite_redirect',0);  // 0=before (most) 'parse_request' calls
function oldsite_redirect() {
  if (isset($_GET['lid'])) {
    global $wpdb;
    $sql = "SELECT post_id FROM {$wpdb->postmeta} " . 
           "WHERE meta_key='lid' AND meta_value='%s'";
    $sql = $wpdb->prepare($sql,$_GET['lid']);
    $post_id = $wpdb->get_var($sql);
    if ($post_id) {
      $permalink = get_permalink($post_id);
      if ($permalink) {
        wp_safe_redirect($permalink,301);
        exit;
      }
    }
  }
}

Again, either solution will work; @Bainternet's or mine; your choice which to use.

4
  • hi mike - i like this answer too, like you say it's a much more efficient query than get_posts (which requires a join in this case because we're querying two tables). Commented Mar 23, 2011 at 16:37
  • @Simon Blackbourn - Glad I could help. Commented Mar 24, 2011 at 6:34
  • This one also worked for me. Now I just need to add a rewrite rule.
    – Ciprian
    Commented Mar 14, 2020 at 18:19
  • This worked great for me migrating from Drupal to Wordpress and storing the Node ID in a custom field. Instead of using $_GET however I used $nodePath = explode('/', $_SERVER["REQUEST_URI"]); and changed the IF clause to $nodePath[1] == 'node' so I can then use the ID in $nodePath[2]. You seriously just saved me hours of work doing these manually or with a bunch of data exports and vlookups. Thank you! Commented Oct 12, 2021 at 15:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.