# Set default advanced modules list for courses

**URL:** <https://discuss.openedx.org/t/set-default-advanced-modules-list-for-courses/16614>\
**Category:** Tutor Help\
**Tags:** how-to, tutor, tutor-plugin, sumac\
**Created:** [July 25, 2025, 10:21am UTC](https://discuss.openedx.org/t/set-default-advanced-modules-list-for-courses/16614 "2025-07-25T10:21:56Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![Retr0](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.openedx.org/retr0/32/8020_2.png) [@Retr0](https://discuss.openedx.org/u/Retr0)\
**Post date:** [July 25, 2025, 10:21am UTC](https://discuss.openedx.org/t/set-default-advanced-modules-list-for-courses/16614/1 "2025-07-25T10:21:56Z")

</div>

Hello everyone,

I am trying to setup a default list of advanced modules in order to save course creators the hustle of setting the list themselves manually every time they create a course.

I have taken a look to the following relevant topics:

> [@Set default advanced modules list in Open edX tutor Palm](https://discuss.openedx.org/t/set-default-advanced-modules-list-in-open-edx-tutor-palm/11810):
>
> Hello everyone, I’m using Open edX tutor Palm under Ubuntu. I recently installed some xblocks and I would like to enable them by default for all courses. I have read this article: [Set Advanced Module List by Default in Open edX](https://sibunglon.com/2021/02/20/set-advanced-module-list-by-default-in-open-edx/) Which is exactly what I need but I don’t know how to do it in Open edX tutor. Can anybody help me? Thank you.

> [@Setting default advanced\_modules (xblocks)](https://discuss.openedx.org/t/setting-default-advanced-modules-xblocks/6499):
>
> Hello everyone, I want to set the default value for advanced\_modules without changing the source code. I need to add a couple of xblocks there so that I don’t have to enter them when creating each course. Maybe there is some kind of configuration or some kind of workaround?

Yet none of them have posted anything about the plugin that will achieve this or at least how it should be structured.  
I have managed to create the following plugin:

```auto
from tutor import hooks

# --- 1. Set default ADVANCED_PROBLEM_TYPES ---
ADVANCED_MODULES = [
    "edx_sga",
    "lti",
    "scorm",
    "library_content",
    "annotatable",
    "poll",
    "survey",
    "h5pxblock",
    "pdf"
]

advanced_problem_types = "\n".join(
    f" {{'component': '{component}', 'boilerplate_name': None}}," for component in ADVANCED_MODULES
)

hooks.Filters.ENV_PATCHES.add_item(
    (
        "openedx-cms-common-settings",
        f"""
ADVANCED_PROBLEM_TYPES = [
{advanced_problem_types}
]
"""
    )
)

# --- 2. Add extra pip requirements ---
EXTRA_PIP_REQUIREMENTS = [
    "h5p-xblock",
    "git+https://github.com/blazejwiecha/xblock-pdf.git"
]

pip_lines = "\n".join(f"RUN pip install {req}" for req in EXTRA_PIP_REQUIREMENTS)

hooks.Filters.ENV_PATCHES.add_item(
    (
        "openedx-dockerfile-post-python-requirements",
        pip_lines
    )
)

```

Upon rebuilding the openedx image, I can verify the insertion of the patched setting in the relevant files (assuming common.py should not include the patched setting):

```auto
app@43dfbb27f64c:~/edx-platform/cms/envs$ grep -rnw './' -e 'ADVANCED_PROBLEM_TYPES' -A 10
./common.py:2050:ADVANCED_PROBLEM_TYPES = [
./common.py-2051- {
./common.py-2052- 'component': 'drag-and-drop-v2',
./common.py-2053- 'boilerplate_name': None
./common.py-2054- },
./common.py-2055- {
./common.py-2056- 'component': 'staffgradedxblock',
./common.py-2057- 'boilerplate_name': None
./common.py-2058- }
./common.py-2059-]
./common.py-2060-
grep: ./ __pycache__ /common.cpython-311.pyc: binary file matches
--
./tutor/production.py:285:ADVANCED_PROBLEM_TYPES = [
./tutor/production.py-286- {'component': 'edx_sga', 'boilerplate_name': None},
./tutor/production.py-287- {'component': 'lti', 'boilerplate_name': None},
./tutor/production.py-288- {'component': 'scorm', 'boilerplate_name': None},
./tutor/production.py-289- {'component': 'library_content', 'boilerplate_name': None},
./tutor/production.py-290- {'component': 'annotatable', 'boilerplate_name': None},
./tutor/production.py-291- {'component': 'poll', 'boilerplate_name': None},
./tutor/production.py-292- {'component': 'survey', 'boilerplate_name': None},
./tutor/production.py-293- {'component': 'h5pxblock', 'boilerplate_name': None},
./tutor/production.py-294- {'component': 'pdf', 'boilerplate_name': None},
./tutor/production.py-295-]
--
./tutor/development.py:285:ADVANCED_PROBLEM_TYPES = [
./tutor/development.py-286- {'component': 'edx_sga', 'boilerplate_name': None},
./tutor/development.py-287- {'component': 'lti', 'boilerplate_name': None},
./tutor/development.py-288- {'component': 'scorm', 'boilerplate_name': None},
./tutor/development.py-289- {'component': 'library_content', 'boilerplate_name': None},
./tutor/development.py-290- {'component': 'annotatable', 'boilerplate_name': None},
./tutor/development.py-291- {'component': 'poll', 'boilerplate_name': None},
./tutor/development.py-292- {'component': 'survey', 'boilerplate_name': None},
./tutor/development.py-293- {'component': 'h5pxblock', 'boilerplate_name': None},
./tutor/development.py-294- {'component': 'pdf', 'boilerplate_name': None},
./tutor/development.py-295-]

```

Yet whenever I create a new course the "Advanced’ option in the insert component area does not show up and the advanced module list in the advanced settings is empty.

Any help on achieving this would be greatly appreciated.

tutor, version 19.0.2

---

<div class="post-metadata">

**Author:** ![sarina](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.openedx.org/sarina/32/2308_2.png) [@sarina](https://discuss.openedx.org/u/sarina)\
**Post date:** [July 31, 2025, 3:43pm UTC](https://discuss.openedx.org/t/set-default-advanced-modules-list-for-courses/16614/2 "2025-07-31T15:43:41Z")

</div>

@Maksim_Sokolskiy would someone on your team who worked on the visual configuration for xblocks in Teak maybe have an idea of how to do this on Sumac?

---

<div class="post-metadata">

**Author:** ![Abdul\_Muqadim](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.openedx.org/abdul_muqadim/32/9226_2.png) [@Abdul\_Muqadim](https://discuss.openedx.org/u/Abdul_Muqadim)\
**Post date:** [August 13, 2025, 5:13pm UTC](https://discuss.openedx.org/t/set-default-advanced-modules-list-for-courses/16614/3 "2025-08-13T17:13:48Z")

</div>

Hi @Retr0 @sarina ,  
It’s not currently possible in Open edX/Tutor to automatically have XBlocks appear in the Advanced section of the unit right when a new course is created.  
The ADVANCED\_PROBLEM\_TYPES.append(…) setting you’ve patched doesn’t control that list in Studio’s “Advanced” component — it only affects the internal Advanced section inside the problem component of unit.It adds the xblock into that list of all courses  
Up until the most recent releases (including Sumac), there’s no config, hook, or plugin in Tutor that will auto-populate the Advanced component list for new courses.

 ![image](https://us1.discourse-cdn.com/flex020/uploads/openedx/original/2X/5/51b8b5b81005d06bc381c4300b14995cae5ccd45.png)

---

<div class="post-metadata">

**Author:** ![wowothk](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.openedx.org/wowothk/32/8277_2.png) [@wowothk](https://discuss.openedx.org/u/wowothk)\
**Post date:** [August 21, 2025, 4:31am UTC](https://discuss.openedx.org/t/set-default-advanced-modules-list-for-courses/16614/4 "2025-08-21T04:31:10Z")

</div>

did you find this solution?

---

<div class="post-metadata">

**Author:** ![Retr0](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.openedx.org/retr0/32/8020_2.png) [@Retr0](https://discuss.openedx.org/u/Retr0)\
**Post date:** [August 21, 2025, 6:40am UTC](https://discuss.openedx.org/t/set-default-advanced-modules-list-for-courses/16614/5 "2025-08-21T06:40:41Z")

</div>

Hello, if you read the reply right above yours you will see that it is not possible as specified by Abdul.

---

<div class="post-metadata">

**Author:** ![wowothk](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.openedx.org/wowothk/32/8277_2.png) [@wowothk](https://discuss.openedx.org/u/wowothk)\
**Post date:** [August 29, 2025, 7:07am UTC](https://discuss.openedx.org/t/set-default-advanced-modules-list-for-courses/16614/6 "2025-08-29T07:07:37Z")

</div>

hello @Abdul_Muqadim this is my patch. But in the advanced problem it is not appear. Whats wrong?

 ![image](https://us1.discourse-cdn.com/flex020/uploads/openedx/original/2X/2/2533d7e8f465fdea8725ad2d7d12a3f6e93f794d.png)

```  
hooks.Filters.ENV\_PATCHES.add\_item((

```
"openedx-cms-common-settings",

```

“”"

ADVANCED\_PROBLEM\_TYPES.append({

```
'component': 'negativemarkingxblock',

'boilerplate_name': None

```

})

“”"

))  
```

---

<div class="post-metadata">

**Author:** ![wowothk](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.openedx.org/wowothk/32/8277_2.png) [@wowothk](https://discuss.openedx.org/u/wowothk)\
**Post date:** [August 29, 2025, 8:32am UTC](https://discuss.openedx.org/t/set-default-advanced-modules-list-for-courses/16614/7 "2025-08-29T08:32:22Z")

</div>

Anyway.. for set advanced modules list, I can suggest to doing this. The goal is ensure our expected xblock will be listed in advanced module.

```auto
# signals.py
from django.db.models.signals import post_save
from django.dispatch import receiver
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
from xmodule.modulestore.django import modulestore

@receiver(post_save, sender=CourseOverview)
def add_negativemarking_to_new_courses(sender, instance, created, **kwargs):
    """
    Ensure every new course gets negativemarking XBlock in advanced_modules.
    """
    if created:
        store = modulestore()
        with store.bulk_operations(instance.id):
            course = store.get_course(instance.id)
            if 'negativemarking' not in course.advanced_modules:
                course.advanced_modules.append('negativemarking')
                store.update_item(course, course.published_by)

```

I create also

```auto
# apps.py
from django.apps import AppConfig

class NegativeMarkingXBlockConfig(AppConfig):
    name = "negativemarking"

    def ready(self):
        # This ensures signals.py is imported at Django startup
        import negativemarking.signals

```

and from `setup.py` we can add this entrypoint

```auto
entry_points={
        ... ,
        "django.apps": [
            "negativemarkingxblock = negativemarkingxblock.apps.NegativeMarkingXBlockConfig",
        ],

```

---

<div class="post-metadata">

**Author:** ![Abdul\_Muqadim](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.openedx.org/abdul_muqadim/32/9226_2.png) [@Abdul\_Muqadim](https://discuss.openedx.org/u/Abdul_Muqadim)\
**Post date:** [September 2, 2025, 2:21pm UTC](https://discuss.openedx.org/t/set-default-advanced-modules-list-for-courses/16614/8 "2025-09-02T14:21:06Z")

</div>

**Hi,**

Regarding adding your XBlock to the advanced problem types, you can do it with the following patch:

```auto
from tutor import hooks

hooks.Filters.ENV_PATCHES.add_item(
    (
        "openedx-cms-common-settings",
        """
# Append additional advanced problem types
ADVANCED_PROBLEM_TYPES.append(
    {
        'component': 'h5pxblock',
        'boilerplate_name': None
    }
)
        """,
    )
)

```

Also, don’t forget to add your XBlock in the **`OPENEDX_EXTRA_PIP_REQUIREMENTS`** setting as well.I was abel to add it through these steps

---

<div class="post-metadata">

**Author:** ![mboisson](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.openedx.org/mboisson/32/7551_2.png) [@mboisson](https://discuss.openedx.org/u/mboisson)\
**Post date:** [July 28, 2026, 2:04pm UTC](https://discuss.openedx.org/t/set-default-advanced-modules-list-for-courses/16614/9 "2026-07-28T14:04:22Z")

</div>

Has there been any update on defining default **Advanced module list** since the newer versions of OpenEdX ? In particular, is this possible through a tutor configuration in Ulmo or Verawood ?

---

<div class="post-metadata">

**Author:** ![Abdul\_Muqadim](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.openedx.org/abdul_muqadim/32/9226_2.png) [@Abdul\_Muqadim](https://discuss.openedx.org/u/Abdul_Muqadim)\
**Post date:** [August 11, 2026, 4:45pm UTC](https://discuss.openedx.org/t/set-default-advanced-modules-list-for-courses/16614/10 "2026-08-11T16:45:04Z")

</div>

Hi @mboisson , I’ve just opened a PR for this, it would be great if you could help test it and share your thoughts so we can move it forward and get it merged.

> <https://github.com/openedx/openedx-platform/pull/38965>
>
> \## Description
> 
> Adds an \`advanced\_by\_default\` flag to \`XBlockStudioConfigurati…on\`, so an \*\*operator\*\* can offer an XBlock in
> the \*\*Advanced\*\* component list of every course from Django admin — without \*\*course authors\*\* adding it to
> each course's Advanced Module List, and without operators forking the platform.
> 
> \### The problem
> 
> Studio decides which XBlocks appear under "Advanced" in a unit from two sources:
> 
> 1. \`courselike.advanced\_modules\` — the course's own Advanced Module List, edited per course in Studio's
> Advanced Settings.
> 2. \`DEFAULT\_ADVANCED\_MODULES\` in \`cms/djangoapps/contentstore/views/component.py\` — a hardcoded list added
> to every course by #36532.
> 
> Neither helps an operator who installs an XBlock for their whole site. Option 1 means every course team
> repeats the same manual step for every new course, forever, and forgetting it is silent — the block just
> isn't there. Option 2 is a Python constant, so the only way in is a fork of \`component.py\` or a monkey-patch
> from a plugin.
> 
> This is one of the most repeated operator questions in the community, over several named releases:
> 
> \- \[Set default advanced modules list for courses\](https://discuss.openedx.org/t/set-default-advanced-modules-list-for-courses/16614)
> \- \[Configuring platform wide default advanced settings for new courses?\](https://discuss.openedx.org/t/configuring-platform-wide-default-advanced-settings-for-new-courses/19179)
> \- \[Set default advanced modules list in Open edX tutor Palm\](https://discuss.openedx.org/t/set-default-advanced-modules-list-in-open-edx-tutor-palm/11810)
> \- \[What is the preferred method to add advanced modules to all new courses?\](https://discuss.openedx.org/t/what-is-the-preferred-method-to-add-advanced-modules-to-all-new-courses/5153)
> 
> \### The change
> 
> \`get\_component\_templates\` already unions the course's \`advanced\_modules\` with \`DEFAULT\_ADVANCED\_MODULES\`.
> This adds the XBlocks the operator has flagged to that union. Everything downstream is untouched: the keys
> still pass through \`\_advanced\_component\_types\`, so \`XBlockConfiguration\` (fully disabled XBlocks), Studio
> support levels, and the filtering of XBlocks already offered as basic components all continue to apply.
> 
> Both legacy Studio and the Authoring MFE build their component menu from \`get\_component\_templates\` (the MFE
> via \`get\_container\_handler\_context\`), so no frontend change is needed.
> 
> \*\*Impacted roles:\*\* Operators (new Django admin field); Course Authors (flagged XBlocks appear under Advanced
> with no per-course setup). No learner-facing change.
> 
> \*\*Backwards compatible:\*\* the field defaults to \`False\`, so with an untouched table the behaviour of
> \`get\_component\_templates\` is identical to before.
> 
> \## Why it is shaped this way
> 
> \*\*Why not a Django setting.\*\* That was the original shape of \`DEFAULT\_ADVANCED\_MODULES\` in #36532, and it was
> \[moved out of \`cms/envs/common.py\` during review\](https://github.com/openedx/openedx-platform/pull/36532):
> 
> \> After speaking w/Kyle and Ed, we've come to the conclusion that this should not be a setting in \`common.py\`.
> \> That implies that it can be overridden by the end-user which creates a new interface we don't want. \[…\]
> \> In the future we can figure out what configurable modifiable version of settings we want to expose to
> \> operators but for now just make it so this is visible on all deployments by adding it into the software
> \> instead in the settings file here.
> 
> This PR is that deferred follow-up, and it intentionally does not reopen the settings question.
> 
> \*\*Why \`XBlockStudioConfiguration\`.\*\* It was named in the same review thread as the place this belongs:
> 
> \> In Studio's django configuration there is an xblocks table \[…\] If we were to extend / improve this area of
> \> the platform configuration it would keep the "advanced" vs "common" configuration out of the code and in
> \> django where it is more easily modifiable.
> 
> It is also already the source of truth for "may course authors create this XBlock in Studio", with an admin
> UI operators know. Introducing a separate model or setting would create a second answer to the same question.
> 
> \*\*Why it does not consult \`XBlockStudioConfigurationFlag\`.\*\* That flag governs whether \*support levels\* are
> enforced, and it is disabled on most installs — reading the new field behind it would make the feature a
> no-op almost everywhere. \`disabled\_xblocks()\` is flag-independent for the same reason. Support levels are
> still enforced downstream when the flag is on: an \*Unsupported\* XBlock flagged advanced-by-default is only
> offered to courses that opted in to unsupported XBlocks, which is covered by a test.
> 
> \*\*Why nothing is written to course policy.\*\* An alternative design is to seed \`advanced\_modules\` into each
> course at creation time. That was rejected here because it does not help the courses that already exist, it
> copies the same operator decision into every course's policy where it must then be un-set one by one, and it
> would behave differently from \`DEFAULT\_ADVANCED\_MODULES\`. Like that list, these XBlocks are offered to
> courses without appearing in any course's own Advanced Module List, so consumers of \`course.advanced\_modules\`
> are unaffected.
> 
> \*\*Why \`DEFAULT\_ADVANCED\_MODULES\` is left alone.\*\* The hardcoded list is the platform's own product decision
> about what every site ships with; this PR only adds a second, operator-owned input to the same union.
> 
> \## Supporting information
> 
> \- #36532 — introduced \`DEFAULT\_ADVANCED\_MODULES\` and deferred the operator-configurable version.
> \- Forum threads linked in the Description above.
> 
> \## Testing instructions
> 
> 1. In Studio's Django admin, go to \*\*Xblock django → Xblock studio configurations\*\* and add a configuration
> for an installed XBlock that is not in \`DEFAULT\_ADVANCED\_MODULES\` (e.g. \`done\`, or any XBlock you have
> installed): set \*\*Name\*\*, leave \*\*Template\*\* empty, tick \*\*Enabled\*\*, set \*\*Support level\*\* to
> \*Fully Supported\*, and tick \*\*Advanced by default\*\*.
> 2. Open any course in Studio — including one created before step 1 — and open a unit.
> 3. Click \*\*Add New Component\*\* → the XBlock now appears under \*\*Advanced\*\*, even though the course's Advanced
> Module List (Settings → Advanced Settings) does not include it.
> 4. Untick \*\*Advanced by default\*\* (or \*\*Enabled\*\*) and reload the unit → it is gone again.
> 5. Check the escape hatches: disabling the XBlock in \*\*Xblock configurations\*\* removes it; and with
> \`XBlockStudioConfigurationFlag\` enabled, an \*Unsupported\* XBlock is only offered to courses that allow
> unsupported XBlocks.
> 
> Automated tests:
> 
> \- \`common/djangoapps/xblock\_django/tests/test\_api.py\` — \`default\_advanced\_xblocks\` returns flagged, enabled
> rows only, ignores support level, and is unaffected by \`XBlockStudioConfigurationFlag\`.
> \- \`cms/djangoapps/contentstore/views/tests/test\_block.py\` — a flagged XBlock appears in a course's Advanced
> list without the course listing it, is not duplicated when the course does list it, is removed by
> \`XBlockConfiguration\`, honors support levels when \`XBlockStudioConfigurationFlag\` is on, and is not offered
> to libraries.
> 
> \## Deadline
> 
> None.
> 
> \## Other information
> 
> \- \*\*Migration:\*\* a single additive \`AddField\` with a default; safely reversible. Verified by applying both
> LMS and CMS migrations to an empty MySQL database, and by \`makemigrations --check\`.
> \- \*\*Caching:\*\* the query is cached with \`CacheInvalidationManager\` and invalidated on save/delete of
> \`XBlockStudioConfiguration\`, matching \`deprecated\_xblocks\` / \`disabled\_xblocks\`.
> \- \*\*Possible follow-up (deliberately out of scope):\*\* a management command so distributions can seed these
> rows during init without shelling into Django. Left out to keep this change minimal.

---

<div class="post-metadata">

**Author:** ![mboisson](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.openedx.org/mboisson/32/7551_2.png) [@mboisson](https://discuss.openedx.org/u/mboisson)\
**Post date:** [August 11, 2026, 5:52pm UTC](https://discuss.openedx.org/t/set-default-advanced-modules-list-for-courses/16614/11 "2026-08-11T17:52:35Z")

</div>

Hi @Abdul_Muqadim

Unfortunately, I don’t have a platform setup to run a dev/fork of the whole OpenEdX. Our “development” platform is for developing our themes and configuration on a _release_ version of OpenEdX/tutor. Therefore, I do not know how I can test this.

Perhaps if you have a way to add this change using tutor environment patches, I can apply it to our dev platform.

Also, I think a change in this direction, while welcome, should probably aim wider and include not just advanced modules, but any course advanced settings:

> [@Configuring platform wide default advanced settings for new courses?](https://discuss.openedx.org/t/configuring-platform-wide-default-advanced-settings-for-new-courses/19179):
>
> Hi, Is there a way to configure platform-wide default advanced settings for new courses ? In particular, I would like to pre-define the list of advanced modules (i.e. [Set default advanced modules list for courses - #9 by mboisson](https://discuss.openedx.org/t/set-default-advanced-modules-list-for-courses/16614/9) ), the LTI passports, the Certificates overrides, … Thanks, Maxime Boissonneault
