Redirecting Old Forum URLs to New Discourse URLs using permalinks
If you’ve moved from other forum software to Discourse using one of our import scripts , then you probably want all your hard-earned Google search results to continue pointing to the same content. Discourse has a built-in way to handle this for you as an alternative to writing nginx rules, using the permalinks lookup table .
The permalinks table allows you to set two things: a url to match, and what that url should show. There are a few options for defining where the url should redirect to. Set one of these:
topic_id : to show a topic
post_id : to show a specific post within a topic
category_id : to show a category
external_url : to redirect to a url that may not belong to your Discourse instance
For example, if your original forum’s topic urls looked like http://example.com/discussion/12345
, and the url for that topic after the import is http://example.com/t/we-moved/987
, then you can setup the mapping like this:
cd /var/discourse
./launcher enter app
rails c
Permalink.create(url: '/discussion/12345', topic_id: 987)
Discourse will then perform a redirect with http response status code 301 (permanently moved) to the correct url for topic id 345. The 301 should cause search engines to update their records and start using the new urls.
If you want some urls to redirect away from Discourse, you can do so by setting external_url :
Permalink.create(url: '/discussion/12345', external_url: 'http://archived.example.com/discussion/12345')
Additional Information
To find the id of a subcategory, you can look it up by the slug like this:
Category.find_by_slug('products').id
To delete the permalink for that url, do this:
Permalink.find_by_url("/blah").destroy
There can be only one permalink record per url, so just search by url.
Creating a topic map from MyBB to Discourse
Dan Dascalescu:
I’ve just created a topic map from MyBB to Discourse automatically, using the migration script.
MyBB was set to use SEO-friendly URLs without IDs in them. Now for example when I navigate to /thread-foo-bar
, nginx redirects to /t/foo-bar/12
. Here’s how I did it:
Patch the importer to output lines that end up creating a map file to use for for nginx’s map module . For the MyBB importer, I added this code in create_posts
:
parent = topic_lookup_from_imported_post_id(m['first_post_id'])
if parent
puts "\nXXX #{m['topic_id']}: #{parent[:topic_id]},"
end
After that, I grepped for lines starting with XXX, removed the XXX
, and made the file a JSON object, which I pasted into this script . Change the URLs to your forums, run the script, and its output will be a series of nginx map lines. I saved it as /etc/nginx/mybb2discourse.map
.
2. Configure nginx to “run other websites on the same machine as Discourse” , while making the following modifications to the nginx config file (/etc/nginx/conf.d/discourse.conf
) in order to point nginx to the map file:
insert this at the top of the file:
map_hash_bucket_size 128;
map_hash_max_size 50000; # might have to increase this
map $uri $new {
include /etc/nginx/mybb2discourse.map;
}
then in the server
section, add:
if ($new) {
rewrite ^ $new permanent;
}
Complete the nginx reload and container rebuild steps from the end of the Configure nginx… post linked above.
Would be great if someone who’s better with Ruby patched the importer to output the topic IDs map (or even better, the nginx map directly).
Discourse to WordPress redirect questions
Permalink Normalization
Danny Goodall:
Just wanted to circle back to this to mention a few of the gotchas that I found and perhaps leave some breadcrumbs for future travellers - because I found this hellishly difficult to debug.
Escaping in the permalink normalization string
The format of the permalink normalization string has two components
the Regular Expression string
the Replacement string
They appear, one immediately after the other, in the permalink normalization string like so
Permalink Normalization
Regular Expression Replacement
<-------------------------><------------->
/(this)reallyis(intuitive)/\1reallyisn't\2
Importantly, slashes are treated differently in the different parts of the same string.
A slash (and other regex chars) in the Regular Expression part of the string must be escaped, however, slashes do not need to be escaped in the Replacement part of the same string and will instead be treated literally.
The Format of incoming URL strings
Secondly, and this took me a while to nail down, you match the URL as a relative path description from root but you will not receive the /
as the first part of the string.
For example, if the URL that your old forum uses looked like this…
http://oldforum.com/chat/the-topic-title/post/d9aa09c3-19bd-4c6e-9d8d-a8f1008000a1
…then the URL that your the regular expression in your permalink normalization will match against will look like this…
chat/topic-title/post/d9aa09c3-19bd-4c6e-9d8d-a8f1008000a1
i.e. a path description from root but without the leading /
slash. (I guess that YMMV here depending on the structure of the URLs that you are redirecting - but I don’t think so).
Examples
Here are some examples from my migration project
CATEGORY_LINK_NORMALIZATION = '/(cat)\/(.*?)([#\?].*)?$/cat/\2'
POST_LINK_NORMALIZATION = '/chat\/(.*?)\/(post)\/(.+?)([#\?].*)?$/post/\3'
TOPIC_LINK_NORMALIZATION = '/(chat)\/(.*?)([#\?].*)?$/topic/\2'
The Process
The Old URL is as it sounds - the URL of the item in the old system.
The permalink normalization (recorded in the permalink_normalizations
system setting) will grab the incoming URL (without the leading slash /) and apply the regex match. The resulting normalised URL is then used to match against the URL Match Text entered on the /admin/customize/permalinks
screen.
Last Reviewed by @SaraDev on 2022-06-03T20:00:00Z
Last edited by @martin 2024-12-16T06:03:09Z
Check document Perform check on document: