---
title: "Course List"
manual: "Academic Programs"
version: "main"
permalink: "https://docs.typo3.org/permalink/fgtclb/academic-programs:integrator-program-list@main"
source: "Integrator/ProgramList.rst"
rendered: "2026-10-17T08:47:58+00:00"
---

# Course List {#integrator-program-list}

![Icon of the Course List content element](../Images/Icons/programs.svg)

-   *CType:* `academicprograms_programlist`
-   *Plugin:*

    `AcademicPrograms`, plugin `ProgramList`, action
    `ProgramController::listAction()`

-   *Set:*

    `fgtclb/academic-programs-program-list`, included in
    `fgtclb/academic-programs`

The **Course List** shows the program pages of a storage as cards: the
title of each program, linked to its page, and the facts the site setting
`plugin.tx_academicprograms.card.fields` names, the degree unless a
site names others (see [The facts of a program](https://docs.typo3.org/permalink/fgtclb/academic-programs:program-facts@main)). Above the cards the visitor finds
a sorting and one select per category type, and the list follows a change of
either without reloading the page. A list that finds nothing says
"No programs found."

It is the element for the overview page of the programs of a faculty or of the
whole institution. With its filter and sorting hidden and a few default
categories it is a fixed list instead, all master programs on a landing page
for example. For a compact entry on the home page that leads to such a list,
use the [Course Finder](https://docs.typo3.org/permalink/fgtclb/academic-programs:integrator-program-finder@main).

![A form with sorting and category selects and a "More filters" toggle above the number of programs found and a grid of program cards, each with title and degree](../Images/Screenshots/program-list-default.png)

A program is a page of the page type **Academic program**. The list
finds these pages, not records in a folder, and links every card to the page.
The [Course Data](https://docs.typo3.org/permalink/fgtclb/academic-programs:integrator-program-details@main) element shows the facts of
a program on its own page, and the header of a program page links back to the
list page the site setting `plugin.tx_academicprograms.page.listPid`
names, see [The layout of a program page](https://docs.typo3.org/permalink/fgtclb/academic-programs:program-page-layout@main).

The element renders the template `Program/List.html` with the partials
below `Program/`, among them `SortingAndFilters.html` for the form
and `Item.html` for a card. [The program list](https://docs.typo3.org/permalink/fgtclb/academic-programs:styling-list@main) shows the markup. The
list is rendered on every request rather than from the page cache, because the
programs it shows depend on the selection in the URL and on program pages
elsewhere in the page tree. Speaking URLs for a filtered list are described in
[Route enhancers](https://docs.typo3.org/permalink/fgtclb/academic-programs:configuration-route-enhancers@main). A sorting the form does not offer, in the
URL or in a submission, is ignored, also a list of values where the form sends
one. The default of the extension applies in its place where the element shows
the sorting selects, the preset of the element where it hides them.

## Settings {#integrator-program-list-configuration}

The tab **Configuration** of the content element holds every option.

-   **Hide category filtering**

    -   *Type:* checkbox
    -   *Default:* off

    Leaves out the category selects of the form, together with the active
    filter tags and the reset link of [Active filters, reset link and result count](https://docs.typo3.org/permalink/fgtclb/academic-programs:configuration-active-filters@main). The
    visitor can no longer change the categories, and the list shows what
    [Default categories](https://docs.typo3.org/permalink/fgtclb/academic-programs:confval-program-list-categories@main) presets, also
    when the visitor changes the sorting.

    Categories that reach a list with a hidden filter, from the
    [Course Finder](https://docs.typo3.org/permalink/fgtclb/academic-programs:integrator-program-finder@main) or in the URL of a link,
    narrow the list further and never replace a default category.

-   **Filter types**

    -   *Type:* select, several, ordered
    -   *Default:* empty

    The category types the form offers a select for, in the order chosen
    here. Empty, the site setting
    `plugin.tx_academicprograms.filter.categoryTypes` decides, and
    without that every category type with a category. See
    [Filter types](https://docs.typo3.org/permalink/fgtclb/academic-programs:program-list-filter-types@main) below.

-   **Include subcategories**

    -   *Type:* checkbox
    -   *Default:* off

    A selected category finds the programs that carry the category itself or
    one of its subcategories, and the filter offers a category as soon as a
    listed program carries one of its subcategories. See
    [Matching subcategories](https://docs.typo3.org/permalink/fgtclb/academic-programs:program-list-subcategories@main) below.

-   **Hide sorting**

    -   *Type:* checkbox
    -   *Default:* off

    Leaves out the two sorting selects, **Sorting field** and
    **Sorting direction**. The list is then sorted as
    [Default sorting](https://docs.typo3.org/permalink/fgtclb/academic-programs:confval-program-list-sorting@main) says, also after the
    visitor filtered it, and whatever sorting the URL of a link carries. With
    the filter hidden as well, the element renders no form at all.

![The number of programs found above a grid of program cards, without any form](../Images/Screenshots/program-list-preset.png)

-   **Default sorting**

    -   *Type:* select
    -   *Default:* Title A-Z

    The order of the list until the visitor picks another one:

    -   **Title A-Z**, **Title Z-A**: by the title of the
        program page.
    -   **Last updated (latest first)**,
        **Last updated (latest last)**: by the date in the field
        **Last Update** of the page properties, which an editor sets
        by hand. Pages without that date come together, first in
        **latest last** and last in **latest first**.
    -   **Page sorting (Result may be unexpected)**,
        **Page sorting, reversed (Result may be unexpected)**: by the
        position of each page among its sibling pages in the page tree. That is
        the order of the page tree only while all program pages share one
        parent page. Program pages of several parents are mixed by their
        sorting values, which follow no visible order.

    A filter submitted while the sorting selects are hidden keeps this order.

    Only the items of the select are supported. A value that is not a field and
    a direction, an empty one or a field alone for example, which the form never
    stores but an import or a TypoScript value for a content element without
    the field can produce, is ignored, and the list sorts by title, A to Z. Of
    a field and a direction, an unknown one is ignored on its own and the other
    one still applies, so `uid desc` sorts by title, Z to A.

-   **Default categories**

    -   *Type:* category tree
    -   *Default:* empty

    Categories of the group `programs` the list is filtered by until the visitor
    selects categories of their own. A program has to carry every category
    selected here, so two categories of the same type find only the programs
    that carry both. Select at most one category per category type unless that
    is meant. With [Include subcategories](https://docs.typo3.org/permalink/fgtclb/academic-programs:confval-program-list-include-subcategories@main) switched on, each of them also finds
    the programs that carry one of its subcategories.

    The selects of the form show the default categories as selected, and the
    active filter tags show them as tags the visitor can remove. A selection
    the visitor submits, in the form or through the
    [Course Finder](https://docs.typo3.org/permalink/fgtclb/academic-programs:integrator-program-finder@main), replaces the default
    categories of the category types it carries a select for and keeps the
    others. With [Hide category filtering](https://docs.typo3.org/permalink/fgtclb/academic-programs:confval-program-list-hide-filter@main)
    switched on, the default categories always apply. The tree
    starts at the categories the site setting
    `plugin.tx_academicprograms.categoryRootUids` names, see
    [Category tree root](https://docs.typo3.org/permalink/fgtclb/academic-programs:configuration-category-tree-root@main).

![The Degree select set to Bachelor, a tag "Bachelor" with a remove cross, a "Reset all filters" link, the number of programs found and the matching cards](../Images/Screenshots/program-list-filtered.png)

-   **Show hidden records**

    -   *Type:* checkbox
    -   *Default:* off

    Lists hidden program pages as well, to every visitor, whatever the preview
    settings of the backend user say. Only the hidden state of a page is
    ignored: a start or end date, an access restriction to frontend user
    groups and a deleted page still keep a program out of the list. Use it for
    a list on an access restricted page that previews programs before they go
    online.

-   **Startingpoint**

    -   *Type:* page
    -   *Default:* empty

    The pages below which the list looks for program pages. A program page is
    listed when its parent page is one of the pages selected here, or one of
    their subpages down to the depth of [Recursive](https://docs.typo3.org/permalink/fgtclb/academic-programs:confval-program-list-recursive@main). Select the page or folder the program pages live
    in.

    Empty, the list shows every program page of the installation, on every
    site. Only pages of the type **Academic program** are listed,
    whatever else lies below the selected pages.

-   **Recursive**

    -   *Type:* select
    -   *Default:* 0 levels (only selected page)

    How many levels below the **Startingpoint** the list looks. With
    `0 levels` it lists the program pages directly below the selected pages,
    with `Infinite` every program page anywhere below them. Choose more levels
    when the program pages are sorted into a page or folder per faculty.

    The levels are read as a visitor sees the page tree. The list does not look
    below a hidden page or folder, and [Show hidden records](https://docs.typo3.org/permalink/fgtclb/academic-programs:confval-program-list-show-hidden-records@main) does not change that.

## Filter types {#program-list-filter-types}

The filter form offers one select per category type of the group `programs`.
Which types it offers, and in which order, is set in two places:

| Where | Applies to |
| --- | --- |
| Field **Filter types** of the **Course List** content element, tab **Configuration** | That element. The editor picks the types and orders them. |
| Site setting / constant `plugin.tx_academicprograms.filter.categoryTypes`, default empty | Every program list of the site whose field is empty. A comma separated list of type identifiers, for example `degree,location,program_type`, see [The filters of the program list](https://docs.typo3.org/permalink/fgtclb/academic-programs:configuration-filter-settings@main). |

The field is listed in `ignoreFlexFormSettingsIfEmpty`, so an empty
field keeps the site setting rather than replacing it with an empty value. With
both empty the form offers every category type of the group that has a
category, in the order of the category types of the group. That is what it
offered before the setting existed.

A type is offered only when at least one category of that type exists. A
category of an offered type that no listed program carries is still offered,
as a disabled option, unless the site hides options without results, see
[The filters of the program list](https://docs.typo3.org/permalink/fgtclb/academic-programs:configuration-filter-settings@main). A type the project removed from the group
later is ignored, and so is an identifier that is no type of the group. The
field only offers the types the group has, including those a project adds in
its own `Configuration/CategoryTypes.yaml`.

The filter types decide what the form offers, not what the list accepts: a
link that filters by a category of a type the form does not offer still
filters the list.

The field is labelled with the title of each type. A type a project adds shows
the title its `CategoryTypes.yaml` gives it, and the filter select in the
frontend is labelled with `sys_category.programs.<identifier>` when the
extension or the site has that label, and with the registered title otherwise,
see [Category types of a project](https://docs.typo3.org/permalink/fgtclb/academic-programs:configuration-labels-category-types@main).

The partial `Program/DemandCategories.html` renders the selects from the
variable `{filterTypes.visible}`, the identifiers of the offered types in
their order. Where that variable does not reach the partial, in a template that
renders the partial with arguments of its own instead of `{_all}`, it
offers every type with a category, as before, and the field and the setting
have no effect. To use them, pass `filterTypes` on in a template that
renders the partial. A project that overrides the partial itself and still
loops `{categories.allCategoriesByType}` keeps its own list as well.

The **Course Finder** reads the same setting when its own field is
empty, see [What the finder renders](https://docs.typo3.org/permalink/fgtclb/academic-programs:program-finder@main).

<!-- TODO: no Markdown rendering for "versionadded" -->

The field Filter types of the content element.

## Matching subcategories {#program-list-subcategories}

Categories of the group `programs` can form a tree, a degree for example:

**A degree tree**

```text
Bachelor
    Bachelor of Science
        Bachelor of Science with Honours
    Bachelor of Engineering
Master
    Master of Science
```

By default a selected category finds only the programs that carry that very
category. A visitor who filters by "Bachelor" does not find a program that
carries only "Bachelor of Science", and the filter offers "Bachelor" as a
disabled option as long as no listed program carries it.

The field **Include subcategories** of the **Course List**
content element, tab **Configuration**, off by default, changes both:

-   A selected category finds every program that carries the category itself
    or a category anywhere below it. That applies to a category the visitor
    selects in the filter and to the **Default categories** of the
    element.
-   The filter offers a category as soon as a listed program carries it or one
    of its subcategories. With
    `plugin.tx_academicprograms.filter.hideDisabledOptions` set,
    such a category is kept as well.

Several selections still all have to match: "Bachelor" and "Berlin" find the
programs with a Bachelor degree of any kind in Berlin, not every Bachelor
program and every program in Berlin.

Only categories the visitor can see take part. A hidden category, a category of
a type outside the group `programs`, and everything below either of them are
not part of the tree. A category that names one of its own subcategories as its
parent does not break the list: each of the two finds the programs of the
other.

With the field switched on, assign each program only its most specific
category, "Bachelor of Science" rather than "Bachelor of Science" and
"Bachelor". The parent no longer has to be assigned for the filter, and no
longer shows up in the facts of the program.

The **Course Finder** has the same field for the options it offers,
see [What the finder renders](https://docs.typo3.org/permalink/fgtclb/academic-programs:program-finder@main). The finder does not decide which programs are
found, the list on its target page does. Switch the field on in both elements.

<!-- TODO: no Markdown rendering for "versionadded" -->

The field Include subcategories. Up to 2.x a category matched
only itself, and projects assigned both levels and hid the parent in the
program output again.

## Updating the list without a reload {#program-list-in-place}

When a visitor changes a filter or the sorting of the
**Course List**, the list updates in place: the results, the filter
form, the active filters and the result count are replaced by the ones of the
filtered list, without reloading the page. There is no setting for it.

-   The address bar shows the URL of the filtered list afterwards, the same URL
    a reload would show, see [Feature: Program filter selections have a URL](https://docs.typo3.org/permalink/fgtclb/academic-programs:feature-1790226102@main). The list can still be
    bookmarked, shared and reloaded, and the back and forward buttons of the
    browser step through the selections.
-   The page shows what a reload of that URL shows. All program lists of a page
    read the selection from the same URL arguments, so with two lists on a page
    a change in one of them filters both, with a reload as without one. A list
    that hides its filter or its sorting keeps its own preset for that part,
    see [Two lists on one page](https://docs.typo3.org/permalink/fgtclb/academic-programs:integrator-program-list-two-lists@main).
-   The select the visitor changed keeps the focus, and an opened
    **More filters** stays open.
-   Screen reader users hear the number of programs found after an update,
    through a visually hidden element with the role `status` and the classes
    `ace-status visually-hidden`. It reads the labels
    `list.resultCount.singular` and `list.resultCount.plural`, and
    loading the page announces nothing. The element is hidden by the class
    `visually-hidden` of Bootstrap, so a site without Bootstrap provides that
    class itself.
-   Without JavaScript the form shows a submit button with the label
    `list.submit`, and submitting it opens the filtered list. With
    JavaScript the column of the button gets the attribute `hidden`. A
    stylesheet that gives that column a `display` of its own needs
    `[hidden] { display: none }` as well, as Bootstrap has it.
-   Where the list cannot be updated in place, because the request fails or the
    answer lacks the list, the form is submitted as before and the page reloads.
-   The selects carry no inline `onchange` handler any more, so a site
    with a strict content security policy no longer has to allow inline event
    handlers for the list.

The module is `@fgtclb/academic-programs/frontend/program-list.js`, loaded
on a page whose list renders a filter or a sorting. A site that brings its own
script switches it off, see [Load the script or bring your own](https://docs.typo3.org/permalink/fgtclb/academic-programs:configuration-javascript@main). The module finds
its parts by attributes, so an override of the templates keeps the update in
place by keeping them:

| Attribute | On | Carries |
| --- | --- | --- |
| `data-academic-programs-list` | The wrapper of the list in `Program/List.html` | The uid of the content element, which finds the same list in the filtered page. |
| `data-academic-programs-list-count-one`, `data-academic-programs-list-count-other` | The wrapper | The sentences announced after an update, `%d` standing for the number. Without both of them nothing is announced. |
| `data-academic-programs-list-content` | An element inside the wrapper that holds the form and the results | Nothing. It is the part that is replaced. `data-academic-programs-list-total` on the same element carries the number of programs it shows. |
| `data-academic-programs-list-status` | An empty element with `role="status"` inside the wrapper, outside the replaced part | Nothing. The sentence is written into it after an update. |
| `data-academic-programs-list-form` | The form in `Program/SortingAndFilters.html` | Nothing. A form outside the replaced part is submitted on a change, and the page reloads. |
| `data-academic-programs-list-select` | Each select in `Program/DemandCategories.html` and `Program/DemandSorting.html` | Nothing. Like the form attribute, for a form that carries neither the attribute nor a place in the replaced part. |
| `data-academic-programs-list-submit` | The column around the submit button | Nothing. The module hides it. |

The template, the form partial and the two filter partials each load the
module, so that it runs whichever of them a project overrides. It is loaded
once. A template override from before 3.0 keeps working:

-   An override of `Program/DemandCategories.html` or
    `Program/DemandSorting.html` that keeps the inline `onchange`
    handlers reloads the page on a change of its selects, as before. The
    module leaves those selects to their handlers and drives the others, so
    the selects of the partial that is not overridden keep working. It hides
    the submit button either way.
-   An override of `Program/List.html` without the wrapper reloads the
    page on a change.
-   An override of `Program/SortingAndFilters.html` is updated in place,
    as long as `Program/List.html` is the one of the extension. It has no
    submit button for a visitor without JavaScript until it renders one.
-   An override of both `Program/List.html` and
    `Program/SortingAndFilters.html` reloads the page on a change,
    through the attribute of the selects of the filter partials.

<!-- TODO: no Markdown rendering for "versionadded" -->

## Two lists on one page {#integrator-program-list-two-lists}

All **Course List** elements of a page read the selection from the same
URL arguments. A submission of the form is answered by the first of them on
the page: it redirects to a URL that carries the selection as that element
sees it, the presets it keeps included. For another **Course List**
element of the page, a sorting the first element hides replaces the one
its visitor chose. The default categories of a category filter the first
element hides, and its default categories of the category types its form does
not offer, are added to the categories the visitor chose. Put lists whose
forms hide or offer different parts on pages of their own.
