The syntax of SPIP’s loops

The basic syntax

The simplified syntax for a loop is as follows:

* HTML code HTML + SPIP tags

We saw previously, in the overview of loops and tags, that the HTML code + SPIP tags included in the example above are repeated as many times as the loop can extract records from the database (in other words, once, several times, or not at all).

The important line in this example is:


-  The word BOUCLE (French for "loop") is an instruction given to SPIP to define a new loop and cannot be written any other way: all SPIP loops must start with a BOUCLE command.

-  The n element is the loop’s identifier. It can be either a name or a number and is freely chosen by the webmaster for every loop created (warning: we will take care to name our loops only with alphanumeric characters that do not have diacritical accents and the "underscore"; i.e. characters from the class defined by [a-zA-Z0-9_]. We will see later how it is possible to use several loops in the same template. This is, after all, the key object of the exercise, and because of this it is essential for each loop to have a unique identifier.

If you decide to number your loops, the syntax for loop 5 would be:


If you decide to give a name to your loops, which is usually more convenient and makes your code easier to read, then the name must start with the underscore symbol “_”. For example:


-  The (TYPE) element is essential for defining what kind of items are to be displayed. The syntax is important: the TYPE must be entered between parentheses, with no spaces, in capital letters, and must be one of the types specified by SPIP: ARTICLES, RUBRIQUES, AUTEURS, BREVES, etc. (they are all covered in this documentation).[Note: not strictly true any more - you can create your own extended tables, and you may also refer to database table names explicitly. Refer to the documentation on extending SPIP and the plugins already constructed to help you do so.]

So, continuing with the previous example, we now have:


-  The criteria specified in {criterion1}{criterion2}... are used to define selection criteria for the records to be retrieved from the database (for example, showing the sub-sections in the current section, or other sections at the same hierarchical level, or ...). Criteria are also used to further filter the selection of items and define how they will be sorted. For example, articles can be sorted by their publication dates, or their titles, etc., and then only the first three articles displayed, or only half of the articles, and so on. With a combination of criteria, you can easily make loops which reflect complicated queries. Each criteria is coded between opening and closing braces, or they may be entered together within a single pair of braces but with spaces between them. As an example, the following loop will display “the list of the 5 most recent articles by the current author”:

<BOUCLE_same_author(ARTICLES){id_auteur}{par date}{inverse}{0,5}>

For each type of loop a detailed description of the various criteria which can be used, together with the syntax for using them, is given in this documentation. Some criteria work for every type of loop, others are specific to loops on only certain kinds of objects.

Full Syntax

The syntax shown above can be completed by conditional elements. Apart from displaying items inside a loop, SPIP also lets you indicate what to show before and after a loop depending on whether that loop returns any results or not.

The full syntax is as follows:

* Optional HTML code before
* HTML code + SPIP tags
* Optional HTML code after
* Alternative HTML code if there are no results

The optional “before” code (preceded by <Bn>) is displayed only if the loop returns at least one result; it appears before the loop’s results.

The optional “after” code (ended by </Bn>) is shown only if the loop returns at least one result; it appears after the loop’s results.

The alternative code (ended by <//Bn>) is displayed instead of the loop, thus replacing the optional “before” and “after” codes, if the loop doesn’t return any results at all.

For example, the code:

 This section has the following elements:
  This section does not have any articles.

will display the following results, depending on the circumstances:

-  if there is only one article:

This section has the following elements:
   <li>Title of the article</li>

-  if there are several articles:

This section has the following elements:
   <li>Title of article 1</li>
   <li>Title of article 2</li>
   <li>Title of the last article</li>

-  if there are no articles:

This section does not have any articles.

Note: Up to [SPIP 1.7.2], the way SPIP interpreted loops meant it was impossible to place any other loop between <B1> and <BOUCLE1>. However, it was possible to place additional loops in the optional parts located after the definition <BOUCLE1...>. If you really needed a loop in the optional before part, you had to it with the help of <INCLURE()> see documentation). This restriction has been lifted in newer versions of SPIP.

Shortcut syntax

Since SPIP 2.0, it has been possible in certain cases to use a shorthand method for coding the loops.

As such, if you only want to retrieve the total number of records returned in the query (with the #TOTAL_BOUCLE tag), you can write:


in place and instead of:


This shorthand form can also be useful whenever you’re only looking to fill up a "doublons" (duplicates) table:

<BOUCLE_a(ARTICLES) {criteria ...} {doublons}/>

Criteria for a cascading environment

As explained above, criteria are used to select the items for a loop. Some of these criteria work depend on the environment in which the loop is placed.

For example, if you want to have a loop “Display the articles of this section”, you need to know which section is targeted. This is what is meant by the environment.

-  The environment given by the URL

When you visit a page on a SPIP site, its address usually contains a variable.
For instance: spip.php?rubrique15 (prior to SPIP 1.9, the URL was written as: rubrique.php3?id_rubrique=15)

This variable (id_rubrique) defines an initial environment. Thus, the loop “Display the articles of this section” will be interpreted as: “Display the articles of section 15”.

And if you call the very same template, with the following URL:
the loop will become “Display the articles of section 7”.

-  The environment provided by other loops

When loops are nested within each other, the inner loop inherits the environment of the one surrounding it. This creates a cascading environment.

Let’s have a look at the following pseudo-structure:

<BOUCLE_articles: (shows the articles from this section)>
  Title of the article
  <BOUCLE_authors: (shows the authors of this article)>
    Name of the author

You can see that:
-  the first loop (BOUCLE_articles) displays the articles of the section, where the latter is defined by the environment given in the URL (id_rubrique=15 for example);
-  this loop returns one or several articles;
-  each time the BOUCLE_articles loop executes, it provides a different environment: that of the current article (id_article=199 for example);
-  the inner loop, (BOUCLE_authors), will be triggered each time that the BOUCLE_articles performs one loop. As each time the environment provided by the outer loop is different, so the meaning of BOUCLE_authors, which, on its own, would be: “show the authors of this article”, will become successively: “show the authors of the first article”, “show the authors of the second article”, and so on.

You can see that by nesting loops within each other it is possible to build a very useful structure, with inner loops inheriting environmental variable values from their parent outer loops. The environment of the outermost loop is inherited from one or more parameters in the URL which calls the page.

Nested loops and successive loops

Just as you can nest loops, each loop being placed within the context of another loop, you can also write loops one after the other; successive loops don’t have any influence on each other.

For instance, the template for a section usually consists of the following elements:

  <ul>Title of the section
    <li>Title of the article</li>
    <li>Title of the sub-section</li>
  <ul>There is no section at this address.</ul>

The outer loop (BOUCLE_section) depends on the variable passed by the URL of the page (id_rubrique=15 for example).

The other loops (BOUCLE_articles and BOUCLE_subsections) are placed within the first loop. If there is no section 15, the outer loop will not return any results (the alternative code “There is no section...” will be shown), and the two loops inside it will be totally ignored. But if there is a section 15, then the two inner loops will be analysed.

The two inner loops are written one after the other. So even though they both depend on the outer loop, they are independent of each other. Thus, if there are no articles in section 15 (BOUCLE_articles), the list of sub-sections in section 15 (BOUCLE_subsections) will still be displayed and vice-versa.


Two tags make it possible to count the number of results in a loop:

-  #TOTAL_BOUCLE gives the total number of results returned by the loop. It may be used anywhere within the loop syntax: in the main body of the loop, within the optional before/after parts, or even in the alternative, “no results”, part.
For example, in order to display the number of documents associated with an article:

  <BOUCLE_doc(DOCUMENTS) {id_article}></BOUCLE_doc>
  [There are (#TOTAL_BOUCLE) document(s).]

Note: If the main body of the loop does not contain any text (as is the case with <BOUCLE_doc> above, which only counts the number of results), then #TOTAL_BOUCLE needs to be placed in the alternative part following the main loop (between </BOUCLE_doc> and <//B_doc>).

-  #COMPTEUR_BOUCLE increases each time the loop loops, and gives the number of the current loop. It can be used to number the results:

<BOUCLE_art(ARTICLES) {par date} {inverse} {0,10}>

Author mathieu, bealach, Paolo Published : Updated : 26/10/12

Translations : عربي, català, Deutsch, English, Español, français, italiano, Nederlands, русский, українська