Help! I need to redirect /p/?

A client’s substack migration had posts with /p/post-name. I wrote a regex redirect rule to /postname/ and thought the problem was fixed.

And then, today he tried to preview a post, and got a 404. Apparently the post preview names those unpublished posts /p/uuid , which then redirects them, which breaks the preview.

So… I’ll file a Github issue, because the preview probably should ignore the redirects file. But meanwhile, if anyone has a suggestion that doesn’t involve writing 100 individual redirects into redirects.yaml, I’d be most appreciative. :slight_smile:

(This post makes finding the problem sound a LOT simpler than it actually was. That’s an hour of my life I’m not getting back!!)

@Cathy_Sarisky, have you considered using a rewrite in Nginx?

location /p {
 rewrite ^/p(/.*)$ $1 last;
}

Previews are built deeply into the frontend with a hardcoded url of /p/:uuid/ as you discovered. You’re right they probably should ignore redirects, but changing that would be significant and is unlikely to happen outside of a huge rewrite of the frontend.

The best solution I can think of is to use a regex match for /p/ followed by not-a-uuid as they have a very specific structure.

I asked ChatGPT to write this regex, and it gave me this:

const regex = /^\/p\/(?![0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$)/;

const url1 = '/p/abc123';
const url2 = '/p/12345678-1234-5678-1234-567812345678';

console.log(regex.test(url1)); // Output: true
console.log(regex.test(url2)); // Output: false

Looks like it would work!

Ghost pro, so nope. :)

1 Like

Great idea, Hannah, thank you! :)

Fortunately, the migrated content doesn’t have uuid slugs!

For anyone who needs it in the future, this is what worked. (I needed to capture, not just match)

  ^\/p\/((?![0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\/$)[A-z0-9-_.]+)\/$: /$1