Assistance with Redirects

Hi all,
I’ve been working recently on migrating my Wordpress blog over to Ghost - and all has gone well so far. One of my final steps before migrating is figuring out how to redirect content from my old URL / page structure. Possibly poor planning on my part, but my Wordpress blog has been using the ‘Plain’ permalink structure - which uses a query string of ?p=.

I’m having a little trouble getting Ghost to match this in a redirect. Running 3.21.0 on a local docker container while working on the migration.

I have tried a handful of regex & non-regex combinations to match the inbound query parameter for the redirect - but every time it seems Ghost ignores it and lands me on the home page instead.

Example below of a few things I’ve tried:

  "from": "/?p=999" ,
  "to":  "/new-url/",
  "permanent": true

  "from": "^\/\\?p=999$" ,
  "to":  "/new-url/",
  "permanent": true

Am I missing something simple here - or is this maybe not a supported configuration?

Also - I did find an open issue ( that sounds similar, but maybe someone more familiar could clarify if that would be causing my issue as well.


Hey @0x2142 :wave:
Are the old post URLs numerical? Is /?p=999 a real example post? Or are they /?p=old-url?

Hi @DavidDarnes -
Yep, the post URLs are numerical. While 999 is an example number, it is a real representation of what the URI to a single post would look like.

Ah I see. In that case rather than creating an overly complex regex you should collate all the legacy URLs and construct a list of redirects to their new slug counterparts. It’ll be a little time consuming but will ensure they redirect properly. Plus there won’t be a regex in your redirects that may cause problems later.

Hmm - Maybe I might be mis-understanding what you’re saying. What I was trying to do is match the exact URI (ex /?p=999) and always redirect to the new post slug (/new-post-location/). Not really trying to do anything fancy - but for the life of me I cannot get ghost to redirect with those incoming URI query strings. I did try a plain ‘from’ URL (ex. /test/) to a new post and it worked no problem. However, with the original URI ghost seems to ignore the redirect & I just land on the ghost home page.

To your point - I do understand that creating a static list of redirects that match the old post URI to the new matching slug would be time consuming, but I am good with that - so long as I can get it to work :slight_smile:

1 Like

Sorry I’ve overcomplicated your query, I thought you were wanting to use regex on a series of links.

I’m testing this out locally and also can’t redirect the URL. “Regular” URLs work, such as /page-slug/ and /new-page-slug/. Maybe there’s a way to escape the characters :thinking:

1 Like

Glad to see I’m not going crazy (yet, at least). I wasn’t able to get it to work natively, which is what led me down the regex path to try and escape the character - but no luck on that front either.

Well - Ultimately I had hoped that I would be able to do this with the native Ghost redirects… but since that doesn’t seem to be the case at this time, I’m just going to use Apache to redirect once I move to prod.

Thankfully - the Ghost export from Wordpress exports the original post ID, so it was easy enough to write a bit of Python to generate all of the rewrite code.

If it helps anyone else, here is the script I used. It will take in the wp_ghost_export.json and dump out a file that contains the Apache rewrites:

import json

with open('./wp_ghost_export.json', 'rb') as wpexport:
postdata = json.load(wpexport)['data']['posts']
postdict = {post['id']:post['slug'] for post in postdata}
with open('./rewrite.txt', 'w') as rewrite:
    for postid in postdict:
        rewrite.write("RewriteCond %%{QUERY_STRING} ^p=%s$ [NC]\r\n" % postid)
        rewrite.write("RewriteRule ^(.*)$ /%s? [R=301,L]\r\n\r\n" % postdict[postid])
1 Like

Sorry I wasn’t able to help in this case, but glad you found a solution. Also grateful you shared your solution, other members of the community will benefits from it I’m sure :blush: