Context-scoped XBlock Fields
Braden MacDonald <email@example.com>
Calen Pennington <firstname.lastname@example.org>
There is currently no standard way for XBlocks to define data fields such that content, settings, or user input can be shared among multiple XBlocks within a particular “context” such as a course. Such “course-scoped” or “context-scoped” fields are a common requirement; for example, an author may wish to specify the default “number of attempts allowed” once for all problems in a course, or a video player XBlock may want to “remember” the user’s preferred video playback speed for videos within a particular course.
This OEP proposes a new mechanism for defining XBlock fields that are explicitly scoped to a particular context. The generic term “context” refers to a course, content library, blog post, or any other place where XBlocks can be used (see “Rationale”).
The XBlock API uses the abstract notion of “scopes” to associate each field
with particular environment(s) and user(s). A field’s
Scope is generally a
composite property, defined as the combination of a
UserScope, and a
For reference, the
UserScope can have three values (no changes to these are
NONE: data not related any particular user, that does not change while
users interact with the XBlock
ALL: data not related to any particular user, but which may be modified
during user interactions
ONE: data related to an individual user
BlockScope can have the following values:
USAGE: “The data is related to a particular use of a block in a course.”
DEFINITION: “The data is related to the definition of the block” (one block definition can be used multiple times in a course or even among multiple courses).
TYPE: “The data is related to all instances of this type of XBlock.”
ALL: “The data is common to all blocks.”
XBlock runtimes would generally not be expected to implement every possible
UserScope. Instead, certain “named scopes”
are defined, which are the only scopes that most runtimes support:
The existing named scopes, and an example use case for each, are as follows:
Scope.content (UserScope.NONE, BlockScope.DEFINITION):
Example: The text of a multiple choice question
Scope.settings (UserScope.NONE, BlockScope.USAGE)
Example: The number of attempts allowed for a problem
Scope.user_state (UserScope.ONE, BlockScope.USAGE)
Example: The student’s answer to a multiple choice question
Scope.user_state_summary (UserScope.ALL, BlockScope.USAGE)
Example: The number of students who have answered the question (side note: there is no locking or atomicity for XBlock field writes, so in practice this field is currently of little use in a MOOC)
Scope.user_info (UserScope.ONE, BlockScope.ALL)
Example: user age (note: this scope seems little-used and overlaps with the user service)
Scope.preferences (UserScope.ONE, BlockScope.TYPE)
Example: (For a video XBlock) Boolean setting to prefer YouTube or non-YouTube video playback.
As one would expect,
Scope.preferences fields in the
Open edX platform are implemented globally, and not scoped to the course that
uses them. There is currently no standard, extensible way to use XBlock fields
to store data that is scoped to a particular “context,” such as a course,
although this is a common need.
In the absence of a formal method for achieving context-scoped fields through the XBlock API, many other solutions have been put in place, such as: adding custom Django models to XBlocks, storing fields on the root “course” XBlock, defining inherited fields using InheritanceMixin, using edx-submissions as a generic data store, and more.
It is hoped that the new canonical mechanism described by this OEP can provide consistency, improve interoperability, allow new types of behavior to be implemented by XBlocks, and give both authors and learners additional control over learner interactions with XBlocks.
To support context-scoped fields,
BlockScope will allow a new value:
CONTEXT. This new
BlockScope will denote data that is related to all
instances of this type of XBlock within a particular context.
A “context” is defined by the runtime but is usually a “course” or the nearest equivalent. In the Open edX platform, the context may be a course or a content library. Different runs of the same course would be considered different contexts and would not share data, though UserScope.NONE fields would be copied when creating a new course run. On other platforms, a “context” could be defined as a blog post or a textbook.
As is the situtation today, XBlock runtimes would generally not be expected to
implement every possible combination of
Instead, XBlock runtimes are encouraged to implement these new named scopes,
which would be defined in the XBlock python package:
Scope.context_settings (UserScope.NONE, BlockScope.CONTEXT)
Example: For an LTI XBlock, a list of the LTI provider URLs and secrets used in the course
Example: For a discussions XBlock: Enable or disable discussions in this course, as well as settings like “allow anonymous discussion posts”, “allow anonymous discussion posts to peers”, “discussion blackout dates”, etc.
Scope.context_preferences (UserScope.ONE, BlockScope.CONTEXT)
To avoid performance issues, runtimes are not required to support field values larger than 4 KiB for fields that use this scope. This restriction is intended to avoid the temptation to use this type of XBlock field for logging or message passing. Such uses could cause data loss or performance concerns, because the XBlock API does not support appends nor locking for field data.
Example: Enable or disable notifications about new discussion posts in this course
Example: Video playback speed for this course
Example: An XBlock in which students “accumulate building blocks over the course of the semester” (PLAT-325)
An XBlock which uses
Scope.context_settings fields will need a way for
content authors to edit the data in those fields. (e.g. when creating a course,
the course author may wish to change course-wide settings for the discussion
XBlock used throughout that course.)
A new XBlock view,
context_settings_view shall be used for this purpose.
Just like the existing studio_view defined by edX Studio, this new view will
allow an XBlock to return an arbitrary HTML Fragment which contains a form or
other UI for editing its
It is expected (but not required) that runtimes like edX Studio which want to
support editing of context-scoped fields will define a list of XBlocks that are
enabled within a particular context/course, and will display a list of XBlocks
that define the
context_settings_view. Clicking on the name of that XBlock
would display the HTML fragment and allow the author to edit the context-scoped
When serializing a course with
Scope.context_settings fields to Open
Learning XML (OLX), any context-scoped fields could be described within a new
<xblock-settings> XML element that is a child of the
This would typically be found in
course/course.xml. Each XBlock class that
Scope.context_settings field data could be represented as a child
<xblock-settings>, with the name of the element matching the
XBlock’s entry point name.
An example follows:
<course display_name="Example Course" language="en" advanced_modules='["drag-and-drop-v2", "lti_consumer", "xblock-dalite"]'> <chapter url_name="6915ee3dd6ab403d8c05c0ea3180a0ee"/> <wiki slug="A.B.C"/> <xblock-settings> <discussion allow_anonymous_discussion_posts="true" discussion_blackout_dates='[["2015-09-15", "2015-09-21"], ["2015-10-01", "2015-10-08"]]' /> <lti_consumer lti_passports='["myapp:key1:secret1", "otherapp:key2:secret2"]' /> <xblock-dalite dalite_lti_passports='["dalite-ng-demo:https://dalite-ng-demo.example:key:secret"]' /> </xblock-settings> </course>
The reasoning behind the above provisional spec is as follows:
Conceptually, in the OLX format, all course content and all XBlock fields are
serialized as XML nodes, within a root
<course> node (docs). The entire
course’s XML may be in a single course.xml file or spread out into multiple
files and subdirectories, where the subdirectory name is the XBlock entry
point name (XML node name) and the file name is the block ID (
Since context-scoped fields are XBlock fields just like Scope.content fields, they should be serialized to OLX the same way (XML, not JSON).
Many existing course-scoped settings that are analogous to context-scoped
fields (discussion settings, LTI passports, etc.) are currently stored as
attributes on the
<course> XML element.
The option of serializing context-scoped fields as namespaced attributes on
<course> element is not feasible as it would be messy and conflicts
with the current approach where almost every attribute is an XBlock field
belonging to the course XBlock.
<xblock-settings> is suggested as a wrapper to keep these new XML nodes
organized and indicate their purpose clearly.
Many of the ideas in this proposal are driven by the desire for new types of functionality to be implemented via XBlocks, and thus to be pluggable and easily installed, enabled, or disabled for each Open edX installation or each course.
The idea of naming the new scope “context” comes from other technologies such as LTI, where the term “context” is used analogously. For example, when embedding an LTI tool into the Open edX LMS, the LMS will pass the current course ID as the LTI “context” parameter.
Previous discussions of note include:
On 2016-07-08, the author met with several stakeholders from edX (Calen Pennington, David Ormsbee, and Robert Raposa) to discuss course-scoped XBlock fields. The discussion tended toward using “context” as an additional dimension (see “Context as a New Scope Dimension” in “Rejected Alternatives”), but we did not think of any use cases for 8 of the 12 additional scopes that would be created by defining an additional dimension.
Other related proposals of note include:
https://github.com/edx/XBlock/pull/317 - XBlock field sharing
This OEP introduces new field scopes but does not remove or modify any existing functionality. XBlock authors that add new fields to their XBlock may opt-in to using this feature.
XBlock runtimes may choose to implement context-scoped fields or not. Attempting
to access a context-scoped field in a runtime that does not support such fields
should simply return the default value of the field. Attempting to modify such a
context-scoped field in a runtime that doesn’t support such fields should raise
Some existing XBlocks currently use workarounds for the lack of context-scoped fields, such as storing data in the fields of the root ‘course’ XBlock. Converting such existing techniques to use context-scoped fields instead would be best achieved with an XBlock data migration API, which currently does not exist and is outside the scope of this OEP (however, see here for an example implementation).
Should runtimes like the LMS be expected to implement a “Preferences” tab for
each course that allows students to edit all
fields for XBlocks used in that course?
If yes (see previous bullet), can we use a field attribute to allow XBlocks
to opt-out of this auto-generated settings UIs on a per-field basis? This may
best be addressed at the same time as a standard API for definining editor UI
options such as
values_provider as implemented in xblock-utils.
Do we need to consider supporting contexts smaller than a course, such as a section or exam? And if so, could that be done in a future change, such as adding a non-scope field property to select a context which defaults to “course”?
The author’s thought on this is that we likely cannot come up with a reasonable proposal to support every possible use case, and it’s better to offer simple, flexible, easily understandable support for the main “course” use case now.
Should there be a way to define a field such that the runtime will search
through a hierarchy of
BlockScope scopes and use the first value found,
such as “check for a
Scope.settings value, then a
TBD. Sample code to implement this feature in the XBlock package and the XBlock SDK/Workbench will be produced once the draft has had some initial scrutiny and feedback.
This proposal originally included two new
CONTEXT_ALL_TYPES; the latter was a proposed new scope that would be
used for field data that is accessible to XBlocks of any type, within a
It also defined two named scopes that used
Scope.context_shared_preferences (UserScope.ONE, BlockScope.CONTEXT_ALL_TYPES)
This scope has been dropped from the proposal as it seems to lack a clear and compelling use case.
Scope.context_shared_settings (UserScope.NONE, BlockScope.CONTEXT_ALL_TYPES)
This scope has been dropped from the proposal as it seems to lack a clear and compelling use case; further, it is unclear how an authoring experience for such fields would work, since no one XBlock could provide an authoring UI for fields that could be shared by many unrelated XBlocks.
The current proposal deliberately does not support inheritance (i.e. a “context” in the LMS would always be a course, not a “section” or any smaller unit, and field values don’t propagate from parent blocks to children), so it is not a replacement for InheritanceMixin.
Initial discussions of this OEP agreed that context-scoped fields should not participate in inheritance. Improving inheritance of fields or making inheritable fields pluggable are worthy goals, but for a separate proposal.
UserScope, and a
name are combined to
make a Scope for a field. Under this alternative option, a new
RelevanceScope dimension would be added, which could have one of two values:
ALL (default) or
ALL value would represent the current
XBlock API’s definitions, and the
CONTEXT value would mean that the field’s
relevance is limited to one particular context (e.g. that field’s value relates
to one particular course.)
The downside of this is that it creates a large matrix/tensor of scopes:
4 BlockScopes × 3 UserScopes × 2 RelevanceScopes = 24 distinct scope types.
Not only is this more difficult to understand, but there is no value in defining
a “context-specific” version of any
BlockScope.DEFINITION fields. As a result of that and other conflicting or
not useful Scope combinations, it is likely that fewer than half of the 24
possible Scope values would be used.
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.