Skip to content

Question blocks


Question blocks add flexibility to STACK questions by adding functional structures to the CASText. These are new from v4.0 onwards.

For example, you can add in a conditional statement to selectively include materials in the version of the CASText depending on values of variables. This is useful in randomly generated contexts, especially within model solutions and randomly generated diagrams/charts.

For maximum flexibility, blocks can be nested and conditionally evaluated. A body of CASText is then repeatedly processed until all blocks have been interpreted into CASText. This is a core part of CASText and so applied to all appropriate parts of the question.

Note: The parameters to blocks in the question body may NOT depend on the student's answers. This means that you cannot reveal an input block based on student input, well not just by using an [[if/]]-block. But you may still adapt PRT feedback as much as you want. Such adaptation requires persistent modifiable question state and is not currently possible in STACK; however, there is work being done to create systems that would allow it.

General syntax

The syntax is quite similar to XML but preserving the style [[ ... ]] used in the inputs and potential response tree declarations.

[[ block_type param1="value1" param2='value2' ... paramN="valueN" ]]
Some content.
[[/ block_type ]]

This syntax avoids issues with the rich text editors used in Moodle but it is still recommended to use the plain text editor to avoid excess line changes and white space generated by the WYSIWYG editors.


  1. In closing a block you must use [[/ "blockname"]] where "blockname" must be used, and it must match the previous opening block.
  2. White space is tolerated in block definitions and after the / in the closing block, but is not necessary.
  3. The parameters have the following syntax: param1="value1". Blocks define what are valid identifiers and parameters. The identifiers must not be in quotes (and so cannot contain spaces). The parameters must be in quotes, and either param1="value1" or param1='value1' is accepted.
  4. Typically param1 will be a valid Maxima identifier, e.g. a variable name and the value would be a valid Maxima expression.
  5. The parameter value must be surrounded by quotes, and both "value" and 'value' are accepted.

Conditional blocks

The common if statement is written as:

[[ if test="some_CAS_expression_evaluating_to_true_or_false" ]]
The expression seems to be true.
[[/ if ]]

The if block requires a parameter called test and the value must be a Maxima expression which evaluates to true or false.

The if block uses a special syntax expansion that provides it a way to handle else cases. For example,

[[ if test='oddp(rand(5))' ]]
This is an odd block!
[[ else ]]
This is an even block!
[[/ if]]

There is an else if type of structure using elif (Python coders won the syntax selection vote),

[[ if test='oddp(var)' ]]
This is an odd block!
[[ elif test='is(var=0)' ]]
It might be even but it is also zero.
[[ else ]]
This is an even block!
[[/ if]]

Note that you may have to evaluate your expression explicitly. Maxima does not always evaluate predicates to true or false. For example, you might expect p<1 in the following to evaluate to true.

[[ define p="0" /]] \(p\) is now {@p@}.
[[ if test="p<1"]]
\(p\) is less than 1.
[[ else ]]
\(p\) is not less than 1.
[[/ if ]]

However, it remains unevaluated. The true branch is therefore not satisfied. Since 4.4 the behaviour of this block matches normal if-else behaviour in Maxima, you may still meet this problem if you happen to turn simplification off.

To address this explicitly evaluate your expressions as predicates.

[[ if test="is(p<1)"]]

Teachers can also use evaluation with simplification and predicates as follows:

[[ if test="ev(p<1,simp,pred)"]]

It is the responsibility of the question author to ensure that every test in an if block evaluates to true or false.

Foreach loop

Foreach blocks iterate over lists or sets and repeat their content redefining variables for each repetition.

[[ foreach x="[1,2,3]" ]]{#x#} [[/ foreach ]]

You may have multiple variables and they will be iterated over in sync and the variables may also come from Maxima. Should one of the lists or set be shorter/smaller the iteration will stop when the first one ends.

[[ foreach x="[1,2,3]" y="makelist(x^2,x,4)" ]] ({#x#},{#y#}) [[/ foreach ]]

Because the foreach block needs to evaluate the lists/sets before it can do the iteration, using foreach blocks will require one additional CAS evaluation for each nested level of foreach blocks. This has not applied since 4.4. no additional cost is related to this block and it is recommended that any repeption that can be removed is removed using this block.

Define block

The define block is a core component of the foreach block, but it may also be used elsewhere. Its function is to change the value of a CAS variable in the middle of CASText. For example:

[[ define x='1' /]] {#x#}, [[ define x='x+1' /]] {#x#}, [[ define x='x+1' /]] {#x#}

should print "1, 2, 3". You may define multiple variables in the same block and the order of define operations is from left to right so "[[ define a='1' b='a+1' c='a+b' /]] {#a#}, {#b#}, {#c#}" should generate the same output.

Note, the use of define provides an alternative to using the question variables. Variables here are defined on the fly. However, we do not recommend this is done routinely.

  1. the readability of the code will suffer.
  2. question variables are available elsewhere in the question, but define blocks are only available in that CASText. This feature can also be used to your advantage.

Comment blocks

Comment blocks allow you to put content into CASText which will not be seen by students.

[[ comment ]] Place comments here which will not appear to students. [[/ comment ]]

Before 4.4 the contents of the block needed to be syntactically correct CASText. That is no longer the case and you can much more easily use this block to comment our unfinished stuff.

The debug block

The special "debug" block allows question authors to see all the values of variables created during a session in a table. Do not leave this block in a live question!

[[ debug /]]

Empty blocks

Some blocks do not have content. For example, the [[ define x='1' /]] block above does not include content. The following is correct syntax:

[[ define x='1']][[/ define]]

But we think the following is much more direct, and clean.

[[ define x='1' /]]

There are other kinds of [[ emptyblocks /]], which are useful in certain cases and developers of new blocks might like to consider this as a possibility.

While the define block does not generate any visible content, empty blocks may be used to generate output. For example [[ debug /]] does generate output.

JSXGraph block

STACK supports inclusion of dynamic graphs using JSXGraph: The key feature of this block is the ability to bind elements of the graph to inputs of the question. See the specific documentation on including JSXGraph elements.

  // boundingbox:[left, top, right, bottom]
  var board = JXG.JSXGraph.initBoard(divid, {boundingbox: [-3, 2, 3, -2], axis: true, showCopyright: false});
  var f = board.jc.snippet('sin(1/x)', true, 'x', true);
  board.create('functiongraph', [f,-3,3]);

Format blocks

In general CASText is assumed to be written in the format (Markdown, raw HTML, Moodle auto-format) that Moodle defines and which can be selected in the editor if one uses the plain text area editor. However, there are cases where one might need to mix formats withing the CASText itself, one of those cases is the inclusion of content written in another format. In these cases one can wrap the differing part in blocks that declare the format to use for that portion. The blocks used for this are named [[moodleformat]], [[markdownformat]], and [[htmlformat]]. In the end all CASText evaluates down to HTML, even if it were written in Markdown-format it will be rendered down to HTML.

JSString block

A new feature in 4.4 is the [[jsstring]] which makes it simpler to produce JavaScript string values out of CASText content. This may be useful for example when generating labels in JSXGraph. The block takes its content and evaluates it as normal CASText and then excapes it as JavaScript string literal.

var label = [[jsstring]]{@f(x)=sqrt(x)@}[[/jsstring]];
/* Would generate, without the need to manually escape things. */
var label = "\\({f\\left(x\\right)=\\sqrt{x}}\\)";

Note, this block is not designed to output Maxima expressins in JS format. For example, this block will not convert x^2 into x**2.

Include block

A new feature in 4.4 is the ability to include content from an URL. The include block allows one to do that. However, it is not a recommended tool for novices and all users choosing to use it should consider what it means for the future maintenance and shareability of your questions. See the specific documentation on include logic.

Lang block

A new feature in 4.4 is a STACK specific localisation mechanism that allows one to output differing text based on the language the student has chosen in their VLE.

[[lang code='fi']]...Text in Finnish...[[/lang]]

Read more about this in the languages documentation.

Textdownload block

A new feature in 4.4 is the ability to construct a text-file using CASText and to provide a link to it for download. This is obviously a way for serving out randomised data to the student. Do note that you can generate whatever you want as the content of that file, one could even generate a LaTeX template with question specific values for the student to fill things in. Read more about serving data out.

Commonstring block

In some circumstances one might see the [[commonstring/]] block. While it might not be one that an author would use it might appear when working with built-in labels and their localisations. What it does is that it gets a key as a parameter and fetches the matching localised string from STACKs language packs and replaces the block with it. It also provides means for injecting named parameters into those templates with varying simplification and presentation options.

Template block

Since 4.4.2 it has been possible to use templates to handle repetitive content or to override content deeper in libraries. Templates are essentially a way for handling repetition when [[foreach]] does not easily work or when inline CASText based function solutions are inconvenient. While inline CASText is often better it might not work as well as overridable templates when working with libraries.

The template block has two parameters, the first being a name which should be a valid name for a function and the second being the mode parameter that controls the blocks behaviour and is of use especially for library builders. There are three different ways for using this block:

  1. To define a templates value for a given name one simply wraps that value in this block with that name. [[template name="foobar"]]Whatever is {@whatever@}[[/template]]. This will not output anything and can also be done in inline CASText either in the question-variables to effect the whole question or in feedback-variables to effect PRTs.
  2. To output that template, one simply uses the empty block form [[template name="foobar"/]] which will output whatever has been defined as that templates value or a warning about the template not been defined. One can add a mode parameter mode="ignore missing" to not see that warning. Typically, one will use the [[define/]] block to change the values used within the template.
  3. For library makers the most common operation mode is the mode="default" where the contents of the block are used if no overriding definition can be found. The default value will not define a default template and this intentional, if a template is to be shared then it needs to be defined at a global level where it always gets evaluated while default templates tend to be sensible to use even in conditionally evaluated contexts. Basically, if your library has any CASText that could benefit from being overridable you simply give it a name and wrap it with [[template name="libarary_xyz" mode="default"]]...[[/template]] and then maybe document somewhere that this name has this default where these injectable variables have these roles so that people may replace the wording and structure and still use the same values.

Note in the background templates are just functions with CASText values. You can do the same with inline CASText and more importantly building your own functions allows you to use arguments for them and thus makes repetition with varying parameters simpler. For templates no arguments exist, for them the values come from the context where they get placed in, and must therefore be controlled though other means.

Blocks that exist but should not be used

There are other blocks that have roles inside the system and that transfer information required for the operation of the system. If you look at the code these are often called "specialblocks". You can rest assured that there are no realistic use cases for them, even in advanced authoring proceses. Practically, none of these blocks ever exist in written out CASText and are only added in as virtual objects during processing. However, if you ever look at the commands going into the CAS you might see these block names going in and coming out.

For example, [[pfs]] is a special block that gets generated by internal logic when we see plugin files (if you place an image into the WYSIWYG editor) in the text, it works as a marker for those files context so that we can combine text from multiple contexts together and still keep track of the origins when the final product gets rendered.

There are blocks that handle the placeholders for inputs, validation, and feedback. Some others deal with translations between forms and postprocessing special types of content.