From Open Energy Information

Subobjects are a nifty way to create any number sets of fields on a page. For example, you might have pages describing movies, the actors in them and reviews. The basic information about the movie just goes in the movie template. The actors can be combined into a single field and their information looked up as needed (you'd have a different type of page for each actor). But for the reviews, you want to have the person making the review, the number of stars, the actual review, and maybe something else. Having a separate page for each review just doesn't make sense - that's where subobjects come in. The subobject would be the combination of required fields (name, stars, review) and people could easily add another review right from the form. And as you'll see, you can do things like search for all movies reviewed by a particular person, or all movies that have at least 1 five star rating.

The official page describing subobjects is: [MediaWiki SubObjects], but an actual working example is much more helpful.

For the example, we'll create recipe pages, where the ingredients (quantity, ingredient, alternatives) are the subobjects. And there will be a page listing all recipes that include a particular ingredient (chicken).

Keep in mind that in the tutorial, if there is something that I think should work but didn't figure out how to do it, I'll mention it. If you get it figured out, please update the tutorial. Similarly, if something isn't stated properly, please educate me.

The steps to create this are pretty typical and are listed in the Table of Contents.

Create the Properties Used Within the Ingredient Subobject

Here we will create two properties - one for the ingredient and one for the optional alternative (just to make things interesting).

Create the RecipeIngredient property:

* just set it to be a string

Similarly, create the AlternativeIngredient property:

* just set it to be a string

So far, so simple.

Create the Template for the Subobject

This will be used to display the subobject on the recipe page and defines the properties for the fields: and here is what the file contains.

  This is the "IngredientSubObject" template.
  It should be called in the following format:
  | qty=
  | ingredient=
  | alternative=
  Edit the page to see the template text.
  </noinclude><includeonly>{{{qty}}}: [[RecipeIngredient::{{{ingredient}}}]] (alternative: [[AlternativeIngredient::{{{alternative}}}]]) 
  {{#subobject:IngredientSubObject with {{{ingredient|}}}
  | qty={{{qty|}}}
  | ingredient={{{ingredient|}}}
  | alternative={{{alternative|}}}
  • As you can see, the precondition defines the #subobject
  • The item is displayed on a single line - the ingredients will be displayed in a list, with each on its own line. To get that effect, the </includeonly> needs to be on the same line as what is getting displayed to avoid and extra line feed.
  • It'd probably be better to not display the alternative if it doesn't exist - it'll look a little messy on the page when alternatives don't exist
  • Notice that there is no property for qty, which makes sense. However that means we can't get it in our results set on #ask queries.

Create the Recipe Template

Now we can create the Recipe template:, and here is the code.

  This is the "RecipePage" template.

  * '''RecipeDescription''' - describing the recipe
  * '''RecipeInstructions''' - steps to prepare

  It should be called in the following format:

  List of existing [[:Category:RecipePage]]

  [[Category:Formatting Templates|{{BASEPAGENAME}}]]


  (this section does not need to be done here)
  {{#ask: [[{{PAGENAME}}]] [[RecipeIngredient::+]] |?RecipeIngredient=Ingredient |?AlternativeIngredient=Alternative |format=table |mainlabel=-}}


  {{#ifeq:{{#ask: [[{{PAGENAME}}]] [[RecipeIngredient::+]] |?RecipeIngredient=Ingredient |format=count|mainlabel=-}}|0||'''(SubObject) Ingredient List'''}}
  • The template <pre> looks pretty standard, except the subobject is listed too. If this is not included, it might actually be OK, but it's working with it in - so there you have it.
  • You'll notice an #ask query is in the middle of the page. This is not required but is included to point out two things
    1. Subobjects are stored using their own template, outside of the recipe template. That means they'll show up at the bottom of the page rather than within the page. An #ask query should be able to take care of this limitation (without breaking up the recipe template into two pieces.
    2. The results of the ask query will combine all values of each attribute together. So if you have salt twice as an ingredient, it will only show up once in the ingredient column. Now if each instance of salt has a quantity, then both quantities will show up in that column. In many cases, this is confusing.
      • There is suppose to be a way around this limitation, but I was not able to figure it out
      • This same limitation is found when querying for subobjects on other pages, except all the attribute values are combine at the page level. So as you'll see, in that table, each row will be a page.
  • And you'll notice that displaying the ingredients aren't included in the template. That's fine, the IngredientSubObject template that we defined in the previous step will take care of that.
  • Finally, there's an #ask query near the end querying the number of ingredients. This is to put a title on the ingredient section. It is handy to do it this way because IngredientSubObject template just does each subobject independently.

Create the Recipe Form

Separate forms for the recipe and ingredients do not need to be created, it's all in one form.

Create the form at this link: and the file looks like the following.

This is the "RecipePage" form.
To create a page with this form, enter the page name below;
if a page with that name already exists, you will be sent to a form to edit that page.


<div id="wikiPreview" style="display: none; padding-bottom: 25px; margin-bottom: 25px; border-bottom: 1px solid #AAAAAA;"></div>
{{{for template|RecipePage}}}
	<div id="RecipeDescription" class="wikiForm">
		<span class="formLabel">Description</span>
		{{{field|RecipeDescription|mandatory|input type=textarea|autogrow}}}
	<div id="RecipeInstructions" class="wikiForm">
		<span class="Description">Instructions</span>
		{{{field|RecipeInstructions|mandatory|input type=textarea|autogrow}}}
{{{end template}}}

{{{for template|IngredientSubObject|label=Ingredients|multiple}}}
	'''Quantity''' {{{field|qty|mandatory|size=6}}}
	'''Ingredient''' {{{field|ingredient|mandatory|size=32}}}
	'''Alternative''' {{{field|alternative|size=64}}}
{{{end template}}}

{{{standard input|save}}} {{{standard input|preview}}} {{{standard input|changes}}} {{{standard input|cancel}}}

And as you can see above, the form looks typical except for the additional template for the subobject. The critical aspect of this definition is that the template has the multiple parameter. As you'll see when you use the form, a box will automatically be created with an ADD button Each time you press add, a new subobject subform will be created on the page. Create as many subobjects as you'd like.

As a note, you cannot place a template within another template, so the subobject part of the form would appear at the bottom of the page.

That's it. We're ready to give it a try. You'll see that you can remove and rearrange the subobjects - all automatically added for you.

Now Let's Create Some Recipes

Now we're ready to give it a try. If you're not on the form page (, go there now.

Fill in the form with a recipe. There are a few already created but please note, these are incomplete recipes (I'm just trying to demonstrate not pass along recipes, BUT if you did want the actual recipe, just let me know).

At a minimum, begin filling out the form and seeing how the subobject sub-forms work. You can also go to one of the example recipes to see it in action (

When finished (or when viewing one of the existing recipes), you'll see the ingredient subobjects listed at the bottom of the page.

You'll also notice the #ask query results in the middle of the page. Notice how the values for each attribute are combined together. There is suppose to be a way around this limitation, but I have not been able to find it.

NOTE: {{{alternative}}} is getting displayed when that field isn't set. There should be an if condition to only display it when the value is present, but was not included to simplify the page.

NOTE: if there are no results with the #ask query, then check that the properties exist and are properly defined in the IngredientSubObject template. If that looks good, then make sure the attribute names are consistent. And finally, if you've made changes and everything seems to be fine, edit the recipe, adjust the ingredients and save it. Then refresh the page. Sometimes it seems like the property cross references get a little off and editing them helps get everything straightened out.

NOTE: if you see IngredientSubObject appear multiple times at the bottom of the page, then you need to create the template for the subobject (or use the same name).

Querying for Recipes by SubObject

Look for just the chicken recipes and then look for all the recipes with their ingredients. This example page is:

  This page is to demonstrate looking for recipes based on one of the ingredients.
  '''Just getting the list of chicken recipes'''
  {{#ask: [[RecipeIngredient::chicken]]  |format=ul}}
  '''Now find all the recipes, and include the alternative ingredients as well'''
  {{#ask: [[RecipeIngredient::+]] |?RecipeIngredient=Ingredient |?AlternativeIngredient=Alternative |format=table |mainlabel=Recipe}}
  • The first ask query finds all RecipeIngredients that match "chicken" and formats in a list of the RecipePage names - perfect for a table of contents.
  • The second queries for all pages with at least one RecipeIngredient (which are only on RecipePages. You'll see in the results that for each page, all values of each attribute are grouped together, so you can't really tell which alternative belongs to which ingredient. It also combines values; so if a recipe had egg listed twice, it would only appear once in this #ask query results. There is suppose to be a solution for this, but I have not found it.