Recommended replacement for modifyClass("model:composer") when overriding save()

I’m migrating away from the deprecated api.modifyClass("model:composer", ...).

My current override of Composer#save conditionally changes the save behavior, but otherwise needs to call super.save(opts).

I see the new addModelMethod / addModelCallback APIs, but I can’t find an example in core of using addModelMethod to override an existing method while retaining access to the original implementation.

Is addModelMethod intended for overriding existing model methods like this? If so, how should a plugin delegate to the original save() implementation?

Or is there another extension point that should be used for this Composer use case?

I guess it would depend on what you’re overriding the save method to do…

if you are looking to prevent a save based on some condition, you could use our composer-service-cannot-submit-post value transformer

if you’re doing something once the post is created, there’s api.onAppEvent("post:created")

if you’re adding a field there’s api.serializeOnCreate

do any of those fit what you’re looking for?

Thanks! I’m already using composer-service-cannot-submit-post — it handles the service-level check. But the composer model’s save() also checks cantSubmitPost, which includes missingReplyCharacters > 0, so an empty body is still blocked there.

onAppEvent("post:created") is too late because the post never gets created, and serializeOnCreate only adds fields to the request, so it doesn’t help with the body-length validation.

So the remaining issue is bypassing missingReplyCharacters / cantSubmitPost for the first post. Is there a supported extension point for this?

Here’s the current initializer for reference:

@david , would appreciate any input you might have on the best approach here.

The best thing would be to add a new hook to Discourse core which allows you to achieve what you need in a supported way. How about something like this:

So then your plugin would do

api.registerValueTransformer(
  "composer-minimum-post-length",
  ({ value, context: { composer } }) => {
    if (
      siteSettings.discourse_optional_topic_body_enabled &&
      composer.topicFirstPost
    ) {
      return 0;
    }

    return value; // Keep core logic
  }
);

LMK if that works for your use-case and I’ll take the PR out of draft and I can get it reviewed/merged.