Extending UnitBlock class for custom fields and controlling completion mode

My team is building a proof-of-concept using open edx to determine if we want to move off of our current platform. We have two problems we are currently trying to solve that I believe could be solved by extending the UnitBlock xblock class and using our subclass in place of the UnitBlock within cms and lms.

Problem 1

Also described here Micro Learning: Perform task upon user completing each Unit, we are trying to track unit completion of units but as described by Jeff in the linked question we are currently having difficulties doing so with the current model. I think if we were able to use a subclass of UnitBlock, we may be able to set completion_mode = XBlockCompletionMode.COMPLETABLE in order to give ourselves more ability to control the meaning of “complete” in the context of the unit rather than rely on the approximation openedx makes based on child blocks.

Problem 2

We would like to add additional fields to the unit that should be defined per unit once and only once. These fields will be used to categorize units based on custom taxonomies we control. If we were able to use a subclass of the UnitBlock class, we could define the fields directly on that class rather than creating a separate xblock class with validation logic that prevents it from being used multiple times per unit.

I have tried creating subclasses of the UnitBlock and VerticalBlock classes and created entry_points for each of these, but they do not seem to override the existing unit/vertical entry points.

Questions

  1. Is this something that is even possible?
  2. Even if it is possible, is it advisable or are there complications that you could think of that could arise from this method of customization?
  3. If this is not possible, I think we will need to create an xblock for managing the unit categorization. All the xblocks I have worked on and seen so far have been content-related, rather than metadata-related. Is there an existing pattern we could follow for creating an xblock for managing unit metadata?
  4. Is there a way to require an xblock within a unit / prevent an xblock from being used within a unit multiple times?

Thank you!

As far as I know, you “should” be able to implement a custom Vertical XBlock by uninstalling the normal one and installing a subclass of it that has the same vertical entry point. I’m not sure why that wouldn’t be working; perhaps you haven’t removed the existing entry point?

It should be fine as long as you subclass the existing blocks. If you tried to replace VerticalBlock with UnitBlock or replaced VerticalBlock with something entirely custom, then you’d have problems. But swapping out VerticalBlock for a custom subclass which has the same entry point (vertical) should be fine as far as I can think.

Well one option is that you can use the XBLOCK_EXTRA_MIXINS setting to add a mixin class to all XBlocks on the platform, which can define new data/metadata fields and do anything else that you’d like. It applies to all blocks but you can ignore its data and/or make it do nothing for most XBlocks other than vertical.

Another solution is to not store this data using XBlocks at all, but rather store it in a separate table with a foreign key to the XBlocks. That’s what I did in the Tagstore API I previously designed for storing taxonomies in Open edX and associating them with XBlocks (or users or anything else), though I never got to finish that project. See the recent thread Tagging a question in Open edX where someone asked a similar question and I gave a similar answer. You may even want to collaborate with them. A separate table is much cleaner and simpler but the big downside is the data won’t be copied if you e.g. duplicate the XBlock in Studio or re-run the course. So it works well for people using content libraries but probably not as helpful if most of your authoring and tagging happens within courses that are then copied or re-run.

There are hacky ways to do this but no clean way that I know of. It would be better to implement a non-XBlock plugin that renders your custom tagging control in Studio alongside the unit in question, and stores its data in a separate table. You can also do this as an XBlock mixin that adds its control widget to the studio_view or author_view of whatever XBlocks you want, without modifying their code.

@braden thank you so much for the incredibly thoughtful response. One question, how does one go about uninstalling the built-in entry points?

I think you’d have to actually edit this file and then re-install with pip install -e . or similar. I’m not sure if there’s any way to just uninstall an individual entry point otherwise.

Hi @tramck

Were you able to make any progress? What steps did you take to resolve these concerns?

Regards

Hi @Manoj_kumar. For now we implemented the custom fields as a UnitMetadataXBlock. The VerticalBlock still has the standard aggregator completion mode, and we are using the CompletionService to determine whether the vertical is complete each time one of its child blocks is completed. We have thoughts about subclassing the VerticalBlock at some point in the future, but we are trying to solve problems with minimal deviation from the core platform during our early stage development.

Hi Jeff,
So sorry for Late reply its great to hear from you. We tried that thing to complete but we are facing to many error. We are going slow we are facing to many errors. By any chance you are going to opensource it or not because it will be useful for whole community and it will be a great contribution from your side for this community.

Regards

Hi Manoj – our implementation is very specific to our use case, with dependencies on our own taxonomy api’s. Since it is not a generic implementation, it would not be useful for others in its current state. Sorry.

Hi Jeff,
Thank you very much can you share us the basic code so we will make it more robust and opensource the Whole code with community and all credit goes to Opencraft team and your team.

We have just created a basic xblock with hardcoded fields that match our needs. We didn’t do anything fancy to allow dynamic fields to be declared by users. So our code simply leverages existing functionality. There is nothing innovative for us to share or get credit for. Maybe one day…

Thank you Jeff