# Script framework to rearrange topics and categories

**URL:** https://meta.discourse.org/t/script-framework-to-rearrange-topics-and-categories/241964
**Category:** Sysadmins
**Created:** [October 15, 2022, 3:05am UTC](https://meta.discourse.org/t/script-framework-to-rearrange-topics-and-categories/241964 "2022-10-15T03:05:13Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![mcdanlj](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/mcdanlj/32/131829_2.png) [@mcdanlj](https://meta.discourse.org/u/mcdanlj)
#### Post date: [October 15, 2022, 3:05am UTC](https://meta.discourse.org/t/script-framework-to-rearrange-topics-and-categories/241964/1 "2022-10-15T03:05:13Z")

</div>

In order to script rearranging a large Discourse with working with my site leadership, I wrote a simple framework for packaging up a bunch of ruby scriptlets to be driven from a YAML configuration file. This way, I can restore a backup on a staging site, run my script, get feedback, change a few lines of YAML, restore the backup, run the script with new configuration, and repeat until satisfied.

I have almost 600 lines of configuration for my site, and doing that by manual manipulation through the UI would just not happen. Not even once, let alone many time to get it right. I know this because last time I proposed making sweeping changes I quite literally gave up trying. By contrast, with this script I can now complete the whole cycle in just a few minutes per iteration, even though the site has about half a million posts and over 100 categories. This lets me get fast feedback from my site leadership, and I’ll be prepared to migrate my site quickly.

More detailed documentation is in the README file in the repository with the code:

[https://github.com/johnsonm/discourse-site-rearranger](https://github.com/johnsonm/discourse-site-rearranger)

⚠ **This script does no error checking. It’s pretty much crazy to run it on your live site. It is intended to run on a staging site, validate the result, and then be taken live. As the author I still intend to run it this way. If you run it directly on a live site you get to keep all the pieces when it breaks.** ⚠

From the documentation, a configuration file might look like this:

```yaml
---
- describe:
    context: Old Name
    category: 7
    name: New Name
    description: New description of category
    slug: new-slug
- movePosts:
    context: move only faq posts from the Support category to the Documentation category
    source: 3 # Support category ID
    target: 6 # Documentation category ID
    withTag: faq
    hide: false # do not hide the Support category when done
- movePosts:
    context: consolidate How-To category into documentation with how-to tag
    source: 8 # How-To category ID
    target: 6 # Documentation category ID
    addTag: how-to
    hide: true # hide the old How-To category, visible only to Admin

```

The progress output while it’s running might then look like this.

```plaintext
==========
Move hidden categories out of the way so they don't clutter admin view
setHiddenCategory: {:category=>11}
==========
Rename Old Name to New Name
describe: {:category=>7, :name=>"New Name", :description=>"New description of category", :slug=>"new-slug"}
==========
move only faq posts from the Support category to the Documentation category
movePosts: {:source=>3, :withTag=>"faq", :target=>6}
==========

```

To use this, put your YAML file in `/var/discourse/shared/app/tmp/rearrange.yaml` and then:

```bash
cd /var/discourse
./launcher enter app
git clone https://github.com/johnsonm/discourse-site-rearranger.git script/discourse-site-rearranger
ruby script/discourse-site-rearranger/rearrange.rb /shared/tmp/rearrange.yaml

```

**However,** it is reasonably likely that this script won’t do _quite_ everything you need. It’s really a **framework** that makes it very easy to drop in new actions that automate more aspects of a scripted site modification with just a few lines of code. All you need to do is define one method with a few lines of code, and you’ll be able to invoke it properly from the YAML file.

Have you been thinking about improving the organization of your site, but shrinking from using the UI, or wondering how to trust that you’ll be able to replicate your testing on a staging site for making changes live? Take a look and tell me what you think!

---

<div class="post-metadata">

### Author: ![mcdanlj](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/mcdanlj/32/131829_2.png) [@mcdanlj](https://meta.discourse.org/u/mcdanlj)
#### Post date: [October 16, 2022, 4:28pm UTC](https://meta.discourse.org/t/script-framework-to-rearrange-topics-and-categories/241964/5 "2022-10-16T16:28:11Z")

</div>

I’m using this script to create a test site, as a clone of my main site. High visual fidelity is **part of the point** but could make it easy to accidentally post on the wrong site while reviewing changes, and have those accidental posts blown away the next time I refresh the test site.

I first made my test site read-only when I asked for public feedback. But login is disabled while the site is in read-only mode, so they couldn’t log in when I asked them to.

I’ve added a new `publicCategoriesReadonly` action that makes anonymously-visible categories writable only by `:admins` and `:readonly` by `:everyone` in order to allow people to log in and poke around, but help avoid accidentally posting on the wrong site. Now the site as a whole is not in read-only mode, but the public categories are.

---

<div class="post-metadata">

### Author: ![mcdanlj](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/mcdanlj/32/131829_2.png) [@mcdanlj](https://meta.discourse.org/u/mcdanlj)
#### Post date: [October 18, 2022, 2:02am UTC](https://meta.discourse.org/t/script-framework-to-rearrange-topics-and-categories/241964/6 "2022-10-18T02:02:42Z")

</div>

It is possible to reference categories as hashtags by slugs. This script allows moving content of categories together and changing slugs, which would make previous posts no longer link after a rebake. (Before a rebake, permalink redirects would make the links work.)

I have now updated the script to track tags before and after the migration and remap references to changed categories in posts.

---

<div class="post-metadata">

### Author: ![mcdanlj](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/mcdanlj/32/131829_2.png) [@mcdanlj](https://meta.discourse.org/u/mcdanlj)
#### Post date: [October 27, 2022, 4:01am UTC](https://meta.discourse.org/t/script-framework-to-rearrange-topics-and-categories/241964/7 "2022-10-27T04:01:31Z")

</div>

I have added a `migrateRetortToReactions` action to the framework for those of us who have had Retort installed and want to move to a supported plugin.

---

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [October 27, 2022, 10:36am UTC](https://meta.discourse.org/t/script-framework-to-rearrange-topics-and-categories/241964/8 "2022-10-27T10:36:33Z")

</div>

Wow! That’s great news. It would be great if someone could make it a rake task and submit it to the reactions plugin.

I’ll have a look at it soon.

---

<div class="post-metadata">

### Author: ![mcdanlj](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/mcdanlj/32/131829_2.png) [@mcdanlj](https://meta.discourse.org/u/mcdanlj)
#### Post date: [October 27, 2022, 1:00pm UTC](https://meta.discourse.org/t/script-framework-to-rearrange-topics-and-categories/241964/9 "2022-10-27T13:00:25Z")

</div>

Having it as a rake task in the plugin sounds smart to me.

I’ve signed the CDCK CLA so any copyright interest on my part in the resulting work won’t get in the way, and it can be put under the same license as the plugin itself.

Also I could imagine that I got something wrong; if you find anything wrong with it, I’d love to know about it because I plan to run that script on my own site sometime in the next few weeks. 😃

On a larger scale, if you find this framework useful for your own work supporting Discourse installations but would like more error handling, I’d take PRs. I merely want to make sure that any PR to it is from someone who has signed the CLA and agrees that any useful pieces of it can be incorporated into official Discourse, which I know is true for you…

---

<div class="post-metadata">

### Author: ![mcdanlj](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/mcdanlj/32/131829_2.png) [@mcdanlj](https://meta.discourse.org/u/mcdanlj)
#### Post date: [October 28, 2022, 12:42am UTC](https://meta.discourse.org/t/script-framework-to-rearrange-topics-and-categories/241964/10 "2022-10-28T00:42:07Z")

</div>

I discovered in the Retort topic that @angus has a branch with UI-driven conversion, which I had completely missed.

> [@Discourse Retort](https://meta.discourse.org/t/retort-a-reaction-style-plugin-for-discourse/35903/469):
>
> Hey guys, as discussed in the topic above I’ve already written a migration feature of Retort to Reactions, including an admin UI. For it to be production ready the maintainers of Reactions will need to make a slight change to improve the abstraction of the code in the Reactions plugin. Supporting a production level migration between two plugins like this requires significant quality assurance otherwise issues like this can easily occur.

My script dives into internals which could conceivably change someday, and once I’ve done my conversions with this script **I won’t notice if those internals change.** I first tried to do it “the right way” but discovered that the Reactions plugin doesn’t expose an interface that enables this. @angus takes the longer view:

> [@Discourse Retort](https://meta.discourse.org/t/retort-a-reaction-style-plugin-for-discourse/35903/472):
>
> By all means, I didn’t mean to discourage you writing it for your own purposes, but I wouldn’t advise other sites to use it unless they’re familiar with the code and the data structure. The bottom line is that the Reactions Plugin isn’t currently written in a way conducive to a stable migration that will work reliably across environments. If anyone wishes to migrate from Retort to Reactions, [Pavilion](https://pavilion.tech) is handling these manually on a contract basis (email contact@pavilion.tech or PM me). If the …

@pfaffman if you make a rake task, you might want to put it in a PR that also make the changes to the interfaces so that, for example, `created_by` can be passed in, as well as silent, rather than using the “back door” that I did. At that point, the rake task would be there for command-line migrations, and it would simultaneously unlock @angus doing a UI-driven migration.
