Migrate a phpBB3 forum to Discourse

Markdown should work as well, but I guess using <strong> could work around even more edge cases. Mind, mixing HTML and Markdown has some gotchas as well… Here’s a simple Markdown solution:

**multiline\
\
text**

I’m curious, from which version of phpBB are you importing? The conversion of BBCode to Markdown is a lot better for 3.2 than it is for previous versions. Ideally you shouldn’t even see [b] in imported posts anymore.

2 Likes

I guess you’re right, I don’t know why I didn’t think about that first…

I’m migrating from phpBB 3.0.7-PL1.

2 Likes

You will do yourself a big favor if you upgrade to 3.2 before the import. :wink:

Make sure the BBCodes in all posts are migrated to the new storage format by running the phpBB reparser: phpBB • Knowledge Base > phpBB 3.2+ Text Reparser

3 Likes

I thought about that at the beginning, but… I hate computer stuff :sweat_smile:
I don’t know phpBB well and I didn’t want to have to handle any error that could happen during an update from such an old version.

Since the Discourse migration script is compatible with phpBB 3.0, I chose not to upgrade phpBB…
Maybe some bbcode issues I encountered would have been avoided with a phpBB upgrade. Stuff like nested lists, [b] with new lines, etc…:man_shrugging:

But since I started working on the import in December, I’m close to having an import that works well (ideally, the new forum would be online in maybe two weeks…) and I’m not sure I want to experiment right now an update of phpBB, especially if I have to review all the custom import fixes I’ve done to see if the phpBB 3.2 importer manages these things better :sweat_smile:. It would be time-consuming.

That said… I could experiment with stuff this weekend afternoon if I’m bored enough!


edit: I tried; moving on a new server and then upgrading to pbpBB 3.2 is a hassle. HTTPS issues. Cache issues. Other issues. Circonvoluted and frustrating procedures. The official tutorial advises using tools requiring outdated PHP version (hey, PHP 5, long time no see…). Apparently, I’m sometimes bored but not insane - not enough to do this kind of stuff at least.

Gerhard! You’re misleading! Upgrading to 3.2 is not a big favor! :laughing:

But enough talking about phpBB itself… And praise the one-click upgrade from Discourse.

1 Like

Hi,

I’m trying to migrate WordPress users to discourse. I was able to follow the instructions to connect to our WP database and import users in the docker container. I wanted to make sure no emails will be sent during or after the migration because we are using SSO WordPress plugin.

I prefixed the emails with “import_” so they don’t receive in case there are background tasks sending email confirmation after the migration completed.

I see that there is last_emailed_at column set after migration:

I know that it’s set by opts[:last_emailed_at] = opts.fetch(:last_emailed_at, Time.now) in the ImportScripts::Base::create_user()

Is there similar function to admin.email_tokens.update_all(confirmed: true) used in ImportScripts::Base::create_admin where it confirms the email?

I don’t see any log showing the emails sent. Was there emails actually sent? Will discourse try to send emails after I change the email to valid ones?

1 Like

This is off-topic, since this topic is about the phpBB3 migration… :wink:

I recommend using a .invalid domain if you want to make sure that some users will never receive any emails (e.g. foo@mywpimport.invalid). But, if you just want to disable outgoing emails until you are ready, setting the disable_emails site setting to “yes” or “non-staff” is your best option!

Outgoing emails are automatically disabled during an import. The values of the last_emailed_at attribute are probably from Discourse trying to send an email, before it discovered that it isn’t allowed to.

Discourse will definitely try to send emails after the migration.

2 Likes

Thanks, I first tried empty string for the email field and the ImportScript base class generated fake emails with the invalid domain. They also have the last_emailed_at attribute set.

So what you are saying is as soon as I corrected the email from database, discourse will try to send the email? But a normal sign on authenticated by WordPress doesn’t require email confirmation. There’s no way around that with the ImportScript ?

1 Like

My migration is done and successful.
However, I face two issues. Let me know if it’s off-topic.

  1. Some post contents have this kind of content:

    [url=https://www.casimages.com/i/1907271141431956116331631.jpg.html][ 
    [img]https://nsm09.casimages.com/img/2019/07/27//1907271141431956116331631.jpg[/img][/url]
    

    The images are showing in the preview, but broken in the post itself, even after rebuilding the HTML:

    The generated HTML for each image is:

    <p><a href="https://www.casimages.com/i/1907271151181956116331666.jpg.html" data-bbcode="true"><span alt="" class="broken-image" title="This image is broken"><svg class="fa d-icon d-icon-unlink svg-icon" aria-hidden="true"><use href="#unlink"></use></svg></span></a></p>
    

    I encounter this issue on many posts. Do you have any idea to fix that globally?

  2. Like many old forums, old Imageshack links have been broken for a long time, and for ever. But some links now display a Ukraine flag instead of nothing:

    How would you handle this behavior?
    I’m open to any idea, but an admin of the forum has a static save of the whole forum on an old hard drive, where most of the old images are valid (since downloaded and stored locally). I’m thinking that in the future I could maybe create a script that would replace all Imageshack “dead” links by the valid images from the static version. It seems very tricky to do, but for this reason, I’m not sure I want to simply remove all Imageshack links from the forum by replacing them with an empty string or something like that.

1 Like

Is it the line break that’s causing the issue? That would be my guess. You will need to remap those BBCodes to remove the line break. Replace a string in all posts should be helpful.

Maybe convert them to HTML comments for now? You could later replace them with the stored images.

2 Likes

It doesn’t seem that’s the issue:
I added line breaks so the content looks like this:

[url=https://www.casimages.com/i/1907271141431956116331631.jpg.html]

[img]https://nsm09.casimages.com/img/2019/07/27//1907271141431956116331631.jpg[/img]

[/url]

And the result:

image

Example posts:

Yes, that’s a good idea! :+1: So basically, replacing the strings (from the topic you linked) using regexes to target Imageshack links only, right?

2 Likes

So, this is not the issue after experimenting with new lines.

But if I copy-paste the post content into a new post on the same forum, the content is correctly displayed :woozy_face: :question: :


(and also the hotlinked images are successfully downloaded locally)

Vs:

I tried rebaking the post with the broken images (that are correctly displayed in the message preview, see my previous post) but it didn’t fix anything.

As far as I know, the raw content from both posts is exactly the same.

But the cooked content from the first post (second line) leads to broken images:

I’m puzzled.

1 Like

Odd thing:
If I try to rebuild the HTML of any post, I got an error 500:

Logs show a fatal error and a warning:

Screenshot of the log window:

Fatal error:

ArgumentError (wrong number of arguments (given 0, expected 1)) lib/guardian/ensure_magic.rb:11:in 'method_missing' app/controllers/posts_controller.rb:570:in 'rebake' app/controllers/application_cont

plugins/discourse-chat/lib/guardian_extensions.rb:71:in `can_rebake?'
lib/guardian/ensure_magic.rb:11:in `method_missing'
app/controllers/posts_controller.rb:570:in `rebake'
actionpack (6.1.4.1) lib/action_controller/metal/basic_implicit_render.rb:6:in `send_action'
actionpack (6.1.4.1) lib/abstract_controller/base.rb:228:in `process_action'
actionpack (6.1.4.1) lib/action_controller/metal/rendering.rb:30:in `process_action'
actionpack (6.1.4.1) lib/abstract_controller/callbacks.rb:42:in `block in process_action'
activesupport (6.1.4.1) lib/active_support/callbacks.rb:117:in `block in run_callbacks'
app/controllers/application_controller.rb:397:in `block in with_resolved_locale'
i18n (1.10.0) lib/i18n.rb:328:in `with_locale'
app/controllers/application_controller.rb:397:in `with_resolved_locale'
activesupport (6.1.4.1) lib/active_support/callbacks.rb:126:in `block in run_callbacks'
activesupport (6.1.4.1) lib/active_support/callbacks.rb:137:in `run_callbacks'
actionpack (6.1.4.1) lib/abstract_controller/callbacks.rb:41:in `process_action'
actionpack (6.1.4.1) lib/action_controller/metal/rescue.rb:22:in `process_action'
actionpack (6.1.4.1) lib/action_controller/metal/instrumentation.rb:34:in `block in process_action'
activesupport (6.1.4.1) lib/active_support/notifications.rb:203:in `block in instrument'
activesupport (6.1.4.1) lib/active_support/notifications/instrumenter.rb:24:in `instrument'
activesupport (6.1.4.1) lib/active_support/notifications.rb:203:in `instrument'
actionpack (6.1.4.1) lib/action_controller/metal/instrumentation.rb:33:in `process_action'
actionpack (6.1.4.1) lib/action_controller/metal/params_wrapper.rb:249:in `process_action'
activerecord (6.1.4.1) lib/active_record/railties/controller_runtime.rb:27:in `process_action'
actionpack (6.1.4.1) lib/abstract_controller/base.rb:165:in `process'
actionview (6.1.4.1) lib/action_view/rendering.rb:39:in `process'
rack-mini-profiler (3.0.0) lib/mini_profiler/profiling_methods.rb:85:in `block in profile_method'
actionpack (6.1.4.1) lib/action_controller/metal.rb:190:in `dispatch'
actionpack (6.1.4.1) lib/action_controller/metal.rb:254:in `dispatch'
actionpack (6.1.4.1) lib/action_dispatch/routing/route_set.rb:50:in `dispatch'
actionpack (6.1.4.1) lib/action_dispatch/routing/route_set.rb:33:in `serve'
actionpack (6.1.4.1) lib/action_dispatch/journey/router.rb:50:in `block in serve'
actionpack (6.1.4.1) lib/action_dispatch/journey/router.rb:32:in `each'
actionpack (6.1.4.1) lib/action_dispatch/journey/router.rb:32:in `serve'
actionpack (6.1.4.1) lib/action_dispatch/routing/route_set.rb:842:in `call'
lib/middleware/omniauth_bypass_middleware.rb:71:in `call'
rack (2.2.3) lib/rack/tempfile_reaper.rb:15:in `call'
rack (2.2.3) lib/rack/conditional_get.rb:40:in `call'
rack (2.2.3) lib/rack/head.rb:12:in `call'
actionpack (6.1.4.1) lib/action_dispatch/http/permissions_policy.rb:22:in `call'
lib/content_security_policy/middleware.rb:12:in `call'
lib/middleware/anonymous_cache.rb:358:in `call'
rack (2.2.3) lib/rack/session/abstract/id.rb:266:in `context'
rack (2.2.3) lib/rack/session/abstract/id.rb:260:in `call'
actionpack (6.1.4.1) lib/action_dispatch/middleware/cookies.rb:689:in `call'
actionpack (6.1.4.1) lib/action_dispatch/middleware/callbacks.rb:27:in `block in call'
activesupport (6.1.4.1) lib/active_support/callbacks.rb:98:in `run_callbacks'
actionpack (6.1.4.1) lib/action_dispatch/middleware/callbacks.rb:26:in `call'
actionpack (6.1.4.1) lib/action_dispatch/middleware/actionable_exceptions.rb:18:in `call'
actionpack (6.1.4.1) lib/action_dispatch/middleware/debug_exceptions.rb:29:in `call'
actionpack (6.1.4.1) lib/action_dispatch/middleware/show_exceptions.rb:33:in `call'
logster (2.10.1) lib/logster/middleware/reporter.rb:43:in `call'
railties (6.1.4.1) lib/rails/rack/logger.rb:37:in `call_app'
railties (6.1.4.1) lib/rails/rack/logger.rb:28:in `call'
config/initializers/100-quiet_logger.rb:23:in `call'
config/initializers/100-silence_logger.rb:31:in `call'
actionpack (6.1.4.1) lib/action_dispatch/middleware/remote_ip.rb:81:in `call'
actionpack (6.1.4.1) lib/action_dispatch/middleware/request_id.rb:26:in `call'
lib/middleware/enforce_hostname.rb:23:in `call'
rack (2.2.3) lib/rack/method_override.rb:24:in `call'
actionpack (6.1.4.1) lib/action_dispatch/middleware/executor.rb:14:in `call'
rack (2.2.3) lib/rack/sendfile.rb:110:in `call'
actionpack (6.1.4.1) lib/action_dispatch/middleware/host_authorization.rb:92:in `call'
rack-mini-profiler (3.0.0) lib/mini_profiler/profiler.rb:249:in `call'
message_bus (4.2.0) lib/message_bus/rack/middleware.rb:60:in `call'
lib/middleware/request_tracker.rb:202:in `call'
railties (6.1.4.1) lib/rails/engine.rb:539:in `call'
railties (6.1.4.1) lib/rails/railtie.rb:207:in `public_send'
railties (6.1.4.1) lib/rails/railtie.rb:207:in `method_missing'
rack (2.2.3) lib/rack/urlmap.rb:74:in `block in call'
rack (2.2.3) lib/rack/urlmap.rb:58:in `each'
rack (2.2.3) lib/rack/urlmap.rb:58:in `call'
unicorn (6.1.0) lib/unicorn/http_server.rb:634:in `process_client'
unicorn (6.1.0) lib/unicorn/http_server.rb:739:in `worker_loop'
unicorn (6.1.0) lib/unicorn/http_server.rb:547:in `spawn_missing_workers'
unicorn (6.1.0) lib/unicorn/http_server.rb:143:in `start'
unicorn (6.1.0) bin/unicorn:128:in `<top (required)>'
vendor/bundle/ruby/2.7.0/bin/unicorn:25:in `load'
vendor/bundle/ruby/2.7.0/bin/unicorn:25:in `<main>'

It was in safe-mode with all theme and plugins disabled, but this code block mentions on the first line:
plugins/discourse-chat/lib/guardian_extensions.rb:71:in 'can_rebake?'

Warning:

Failed to handle exception in exception app middleware : ArgumentError : wrong number of arguments (given 0, expected 1)

/var/www/discourse/plugins/discourse-chat/lib/guardian_extensions.rb:71:in `can_rebake?'
/var/www/discourse/lib/guardian/ensure_magic.rb:11:in `method_missing'
/var/www/discourse/app/controllers/posts_controller.rb:570:in `rebake'
actionpack-6.1.4.1/lib/action_controller/metal/basic_implicit_render.rb:6:in `send_action'
actionpack-6.1.4.1/lib/abstract_controller/base.rb:228:in `process_action'
actionpack-6.1.4.1/lib/action_controller/metal/rendering.rb:30:in `process_action'
actionpack-6.1.4.1/lib/abstract_controller/callbacks.rb:42:in `block in process_action'
activesupport-6.1.4.1/lib/active_support/callbacks.rb:117:in `block in run_callbacks'
/var/www/discourse/app/controllers/application_controller.rb:397:in `block in with_resolved_locale'
i18n-1.10.0/lib/i18n.rb:328:in `with_locale'
/var/www/discourse/app/controllers/application_controller.rb:397:in `with_resolved_locale'
activesupport-6.1.4.1/lib/active_support/callbacks.rb:126:in `block in run_callbacks'
activesupport-6.1.4.1/lib/active_support/callbacks.rb:137:in `run_callbacks'
actionpack-6.1.4.1/lib/abstract_controller/callbacks.rb:41:in `process_action'
actionpack-6.1.4.1/lib/action_controller/metal/rescue.rb:22:in `process_action'
actionpack-6.1.4.1/lib/action_controller/metal/instrumentation.rb:34:in `block in process_action'
activesupport-6.1.4.1/lib/active_support/notifications.rb:203:in `block in instrument'
activesupport-6.1.4.1/lib/active_support/notifications/instrumenter.rb:24:in `instrument'
activesupport-6.1.4.1/lib/active_support/notifications.rb:203:in `instrument'
actionpack-6.1.4.1/lib/action_controller/metal/instrumentation.rb:33:in `process_action'
actionpack-6.1.4.1/lib/action_controller/metal/params_wrapper.rb:249:in `process_action'
activerecord-6.1.4.1/lib/active_record/railties/controller_runtime.rb:27:in `process_action'
actionpack-6.1.4.1/lib/abstract_controller/base.rb:165:in `process'
actionview-6.1.4.1/lib/action_view/rendering.rb:39:in `process'
rack-mini-profiler-3.0.0/lib/mini_profiler/profiling_methods.rb:85:in `block in profile_method'
actionpack-6.1.4.1/lib/action_controller/metal.rb:190:in `dispatch'
actionpack-6.1.4.1/lib/action_controller/metal.rb:254:in `dispatch'
actionpack-6.1.4.1/lib/action_dispatch/routing/route_set.rb:50:in `dispatch'
actionpack-6.1.4.1/lib/action_dispatch/routing/route_set.rb:33:in `serve'
actionpack-6.1.4.1/lib/action_dispatch/journey/router.rb:50:in `block in serve'
actionpack-6.1.4.1/lib/action_dispatch/journey/router.rb:32:in `each'
actionpack-6.1.4.1/lib/action_dispatch/journey/router.rb:32:in `serve'
actionpack-6.1.4.1/lib/action_dispatch/routing/route_set.rb:842:in `call'
/var/www/discourse/lib/middleware/omniauth_bypass_middleware.rb:71:in `call'
rack-2.2.3/lib/rack/tempfile_reaper.rb:15:in `call'
rack-2.2.3/lib/rack/conditional_get.rb:40:in `call'
rack-2.2.3/lib/rack/head.rb:12:in `call'
actionpack-6.1.4.1/lib/action_dispatch/http/permissions_policy.rb:22:in `call'
/var/www/discourse/lib/content_security_policy/middleware.rb:12:in `call'
/var/www/discourse/lib/middleware/anonymous_cache.rb:358:in `call'
rack-2.2.3/lib/rack/session/abstract/id.rb:266:in `context'
rack-2.2.3/lib/rack/session/abstract/id.rb:260:in `call'
actionpack-6.1.4.1/lib/action_dispatch/middleware/cookies.rb:689:in `call'
actionpack-6.1.4.1/lib/action_dispatch/middleware/callbacks.rb:27:in `block in call'
activesupport-6.1.4.1/lib/active_support/callbacks.rb:98:in `run_callbacks'
actionpack-6.1.4.1/lib/action_dispatch/middleware/callbacks.rb:26:in `call'
actionpack-6.1.4.1/lib/action_dispatch/middleware/actionable_exceptions.rb:18:in `call'
actionpack-6.1.4.1/lib/action_dispatch/middleware/debug_exceptions.rb:29:in `call'
actionpack-6.1.4.1/lib/action_dispatch/middleware/show_exceptions.rb:33:in `call'
logster-2.10.1/lib/logster/middleware/reporter.rb:43:in `call'
railties-6.1.4.1/lib/rails/rack/logger.rb:37:in `call_app'
railties-6.1.4.1/lib/rails/rack/logger.rb:28:in `call'
/var/www/discourse/config/initializers/100-quiet_logger.rb:23:in `call'
/var/www/discourse/config/initializers/100-silence_logger.rb:31:in `call'
actionpack-6.1.4.1/lib/action_dispatch/middleware/remote_ip.rb:81:in `call'
actionpack-6.1.4.1/lib/action_dispatch/middleware/request_id.rb:26:in `call'
/var/www/discourse/lib/middleware/enforce_hostname.rb:23:in `call'
rack-2.2.3/lib/rack/method_override.rb:24:in `call'
actionpack-6.1.4.1/lib/action_dispatch/middleware/executor.rb:14:in `call'
rack-2.2.3/lib/rack/sendfile.rb:110:in `call'
actionpack-6.1.4.1/lib/action_dispatch/middleware/host_authorization.rb:92:in `call'
rack-mini-profiler-3.0.0/lib/mini_profiler/profiler.rb:249:in `call'
message_bus-4.2.0/lib/message_bus/rack/middleware.rb:60:in `call'
/var/www/discourse/lib/middleware/request_tracker.rb:202:in `call'
railties-6.1.4.1/lib/rails/engine.rb:539:in `call'
railties-6.1.4.1/lib/rails/railtie.rb:207:in `public_send'
railties-6.1.4.1/lib/rails/railtie.rb:207:in `method_missing'
rack-2.2.3/lib/rack/urlmap.rb:74:in `block in call'
rack-2.2.3/lib/rack/urlmap.rb:58:in `each'
rack-2.2.3/lib/rack/urlmap.rb:58:in `call'
unicorn-6.1.0/lib/unicorn/http_server.rb:634:in `process_client'
unicorn-6.1.0/lib/unicorn/http_server.rb:739:in `worker_loop'
unicorn-6.1.0/lib/unicorn/http_server.rb:547:in `spawn_missing_workers'
unicorn-6.1.0/lib/unicorn/http_server.rb:143:in `start'
unicorn-6.1.0/bin/unicorn:128:in `<top (required)>'
/var/www/discourse/vendor/bundle/ruby/2.7.0/bin/unicorn:25:in `load'
/var/www/discourse/vendor/bundle/ruby/2.7.0/bin/unicorn:25:in `<main>'

Do this information help?
I’m doing what I can to try to repair these posts, but I’m starting to believe this has something to do with Discourse itself and not something on my side maybe? :person_shrugging:


edit: see the automatically linked post below.


Issue resolved:

Now I just have to rebake all my posts. :wink:


Another edit:

Could have worked for sure, and will for images that still have their old plain URL, but:

  • Since all the old Imageshack broken links were replaced by valid images displaying a Ukraine flag by Imageshack itself, they were automatically uploaded to Discourse, changing their URL to a markdown local image link.

  • Fortunately, all these flags were uploaded to Discourse with identical links (![](upload://sOlmOE8qRgLUJ8cCe6N1JNkDV3Y.jpeg) in my case - excellent Discourse behavior by the way :+1:), which means that they will be very easy to target and remove/replace with something else. :slight_smile:

I’m just writing this to inform people that would encounter the same issue as me after a migration.

4 Likes

It seems like the poll_option_total value is off sometimes. I’m seeing more non-anonymous votes per option than the value of poll_option_total. And all those users exist.

Using GREATEST(..., 0) fixes it. At least, it doesn’t crash.

        SELECT o.poll_option_id, o.poll_option_text, o.poll_option_total AS total_votes,
          GREATEST(CAST(o.poll_option_total AS SIGNED) - (
            SELECT COUNT(DISTINCT v.vote_user_id)
              FROM #{@table_prefix}poll_votes v
                JOIN #{@table_prefix}users u ON (v.vote_user_id = u.user_id)
                JOIN #{@table_prefix}topics t ON (v.topic_id = t.topic_id)
              WHERE v.poll_option_id = o.poll_option_id AND v.topic_id = o.topic_id
          ),0) AS anonymous_votes
        FROM #{@table_prefix}poll_options o
        WHERE o.topic_id = #{topic_id}
        ORDER BY o.poll_option_id
3 Likes

I really want to migrate my company’s phpbb 3.3 forum to Discourse. Does anyone have any idea when that will be supported?

1 Like
3 Likes

Oh wow, thats great! Thanks!

1 Like

If I should start a new thread for this, I apologize in advance.

I’ve got a phpBB forum in a subfolder:

thedomain.com/forum/

I’m planning to use the import script to migrate from phpBB to Discourse in a subdomain; i.e.:

forum.thedomain.com

So, it looks like all I’ll need to do–for the domain and permalinks–is set the following in settings.yml using HTTPS on the new site:

site_prefix:
    # this is needed for rewriting internal links in posts
    original: thdomain.com/forum    # without http(s)://
    new: https://forum.thedomain.com       # with http:// or https://

  # Enable this, if you want to redirect old forum links to the the new locations.
  permalinks:
    categories: true  # redirects   /viewforum.php?f=1            to  /c/category-name
    topics: true      # redirects   /viewtopic.php?f=6&t=43       to  /t/topic-name/81
    posts: true      # redirects   /viewtopic.php?p=2455#p2455   to  /t/topic-name/81/4
    # Append a prefix to each type of link, e.g. 'forum' to redirect /forum/viewtopic.php?f=6&t=43 to /t/topic-name/81
    # Leave it empty if your forum wasn't installed in a subfolder.
    prefix: forum

And then, on the original server, which runs Apache, in the .htaccess with RewriteEngine already on, I’ll need:

RewriteCond %{HTTP_HOST} ^thedomain.com
RewriteRule ^forum/(.*)$ https://forum.thedomain.com/$1 [L,R=301]

If it’s really that easy, this script rocks! :grinning:

I do have a couple of additional questions:

  1. Posts are set to “false” in the permalink settings. I know there are links out there to specific posts, so I’d like them permalinked as well. Is there any reason not to set them to true; e.g., performance or something?
  2. Is the prefix okay without single quotes, or should it be quoted as in the comment?
2 Likes

It will slightly slow down the import, but you shouldn’t worry about that. It’s mostly disabled by default because it’s rarely needed.

Yes, that’s fine.

2 Likes

I ran into a snag as I’m preparing for this import.

The phpBB forum I’m planning to migrate is using a custom BBcode that creates HTML img tags for images stored in folders by year in a directory outside phpBB, but on the same user account on the server. The BBcode takes the following format:

[Gallery]{NUMBER1}|{NUMBER2}|{NUMBER3}|{SIMPLETEXT}[/Gallery]

The {NUMBER1} and {NUMBER2} are integers for the width and height of the image, respectively. The {NUMBER3} is an integer for the year-folder the image is in, and the {SIMPLETEXT} is the image file name. The HTML replacement for the BBcode looks like this:

<img class="postimage gallery-image" src="/gallery/files/{NUMBER3}/{SIMPLETEXT}" width="{NUMBER1}" height="{NUMBER2}" />

What I need to figure out is how to handle this custom BBcode with the migration script, both to convert the custom BBcode to something Discourse can use, and figure out where to put the image files in the file tree for the import.

I took a look at Ruby-BBcode-to-MD, which says it “allows to easily extend this set with custom tags by editing tags.rb.” I took a look at tags.rb, but since this is my first time looking at Ruby code, I’m at a loss as to how to deal with my custom BBcode since its pipe-separated format differs from any of the official BBcodes that the tags.rb file includes which I might have used as a guide.

I don’t have templates/import/phpbb3.template.yml loaded yet, so I’m guessing that will add the Ruby BBcode to MD gem?

So I have questions:

  1. What is the best way to handle this custom BBcode for the migration? Is editing the tags.rb file the way to go? (If so, I’m going to do some research on Ruby coding and maybe regex next, but any hints will be welcome!)
  2. What is the best place to put the image files for this gallery in the import file tree so that they’re saved in Discourse and show up in the imported posts?
1 Like

That gem isn’t really used anymore. From which version of phpBB are you importing? If it’s v3.1 or below, you will need to apply some regex magic in discourse/text_processor.rb at ea2fd75d10e81687334f8d29e0d3e786dbdb4a53 · discourse/discourse · GitHub.

For v3.2 you can add BBCode handling in discourse/xml_to_markdown.rb at a71b219c9a18ad418e330282fde511bcb79ba7c4 · discourse/discourse · GitHub

2 Likes