grav contenido

Colecciones

En Grav, el tipo más común de colección es una lista de páginas que se puede definir tanto en el frontmatter de la página como en el propio Twig. Lo más común es definir una colección en el frontmatter. Con una colección definida, está disponible en el Twig de la página para hacer lo que desees. Al usar métodos de colección de páginas o recorrer cada objeto de página y usar los métodos o propiedades de la página, puedes hacer cosas poderosas. Ejemplos comunes de esto incluyen mostrar una lista de publicaciones de blog o mostrar subpáginas modulares para renderizar un diseño de página complejo.

Objeto de Colección

Cuando defines una colección en el encabezado de la página, estás creando dinámicamente una Colección de Grav que está disponible en el Twig de la página. Este objeto de Colección es iterable y puede tratarse como un array, lo que te permite hacer cosas como:

{{ dump(page.collection[page.path]) }}

Ejemplo de Definición de Colección

Un ejemplo de colección definida en el frontmatter de la página:

content:
    items: '@self.children'
    order:
        by: date
        dir: desc
    limit: 10
    pagination: true

El valor content.items en el frontmatter de la página le dice a Grav que reúna una colección de elementos, y la información pasada aquí define cómo se construirá la colección.

Esta definición crea una colección para la página que consiste en todas las páginas hijas ordenadas por fecha en orden descendente con paginación mostrando 10 elementos por página.

Los enlaces de paginación se agregan solo si el Plugin de Paginación está instalado y habilitado.

Accediendo a Colecciones en Twig

Cuando esta colección está definida en el encabezado, Grav crea una colección page.collection a la que puedes acceder en una plantilla Twig con:

{% for p in page.collection %}
<h2>{{ p.title|e }}</h2>
{{ p.summary|raw }}
{% endfor %}

Esto simplemente recorre las páginas en la colección mostrando el título y el resumen.

También puedes incluir un parámetro de orden para cambiar el orden predeterminado de las páginas:

{% for p in page.collection.order('folder','asc') %}
<h2>{{ p.title|e }}</h2>
{{ p.summary|raw }}
{% endfor %}

Encabezados de Colección

Para indicarle a Grav que una página específica debe ser una página de listado y contener páginas hijas, hay varias variables que se pueden usar:

Resumen de opciones de colección

String Resultado
'@root.pages' Obtener las páginas de nivel superior
'@root.descendants' Obtener todas las páginas del sitio
'@root.all' Obtener todas las páginas y módulos del sitio
'@self.page' Obtener una colección con solo la página actual
'@self.parent' Obtener una colección con solo el padre de la página actual
'@self.siblings' Obtener los hermanos de la página actual
'@self.children' Obtener los hijos de la página actual
'@self.modules' Obtener los módulos de la página actual
'@self.all' Obtener tanto los hijos como los módulos de la página actual
'@self.descendants' Recorrer todos los hijos de la página actual
'@page.page': '/fruit' Obtener una colección con solo la página /fruit
'@page.parent': '/fruit' Obtener una colección con solo el padre de la página /fruit
'@page.siblings': '/fruit' Obtener los hermanos de la página /fruit
'@page.children': '/fruit' Obtener los hijos de la página /fruit
'@page.modules': '/fruit' Obtener los módulos de la página /fruit
'@page.all': '/fruit' Obtener tanto los hijos como los módulos de la página /fruit
'@page.descendants': '/fruit' Obtener y recorrer todos los hijos de la página /fruit
'@taxonomy.tag': photography taxonomía con tag=photography
'@taxonomy': {tag: birds, category: blog} taxonomía con tag=birds && category=blog

Este documento describe el uso de @page, @taxonomy.category, etc., pero un formato más seguro para YAML es page@, taxonomy@.category. Todos los comandos @ se pueden escribir en formato de prefijo o sufijo.

Las opciones de colección han sido mejoradas y cambiadas desde Grav 1.6. Las versiones antiguas seguirán funcionando, pero no se recomienda su uso.

Cubriremos estos con más detalle.

Colecciones Raíz

@root.pages - Páginas de nivel superior

Esto se puede usar para obtener las páginas publicadas de nivel superior/raíz de un sitio. Es particularmente útil para obtener los elementos que componen la navegación principal, por ejemplo:

content:
    items: '@root.pages'

Un alias de '@root.children' también es válido. Usar '@root' está obsoleto, ya que su significado puede cambiar en el futuro.

@root.descendants - Todas las páginas

Esto obtendrá efectivamente todas las páginas de tu sitio, ya que navega recursivamente a través de todos los hijos desde la página raíz hacia abajo, y construye una colección de todas las páginas publicadas de un sitio:

content:
    items: '@root.descendants'
@root.all - Todas las páginas y módulos

Esto hará lo mismo que arriba, pero incluye todas las páginas y módulos publicados del sitio.

content:
    items: '@root.all'

Colecciones Propias

@self.page - Solo la página actual

Esto devolverá una colección que contiene solo la página actual.

content:
    items: '@self.page'

Un alias de '@self.self' también es válido.

Se devolverá una colección vacía si la página no ha sido publicada.

@self.parent - La página padre de la página actual

Este es un caso especial de colección porque siempre devolverá solo el padre de la página actual:

content:
    items: '@self.parent'

Se devolverá una colección vacía si la página está en el nivel superior.

@self.siblings - Hermanos de la página actual

Esta colección recopilará todas las páginas publicadas en el mismo nivel que la página actual, excluyendo la página actual:

content:
    items: '@self.siblings'
@self.children - Hijos de la página actual

Esto se usa para listar los hijos publicados de la página actual:

content:
    items: '@self.children'

Un alias de '@self.pages' también es válido. Usar '@self' está obsoleto, ya que su significado puede cambiar en el futuro.

@self.modules - Módulos de la página actual

Este método recupera solo los módulos publicados de la página actual (_features, _showcase, etc.):

content:
    items: '@self.modules'

Usar el alias de '@self.modular' está obsoleto.

@self.all - Hijos y módulos de la página actual

Este método recupera solo los hijos y módulos publicados de la página actual:

content:
    items: '@self.all'
@self.descendants - Hijos + todos los descendientes de la página actual

Similar a .children, la colección .descendants recuperará todos los hijos publicados pero continuará recorriendo recursivamente todos sus hijos:

content:
    items: '@self.descendants'

Colecciones de Página

@page.page - Colección de solo la página específica

Esta colección toma una ruta de slug de una página como argumento y devolverá una colección que contiene esa página (si es una página publicada):

content:
    items:
      '@page.page': '/blog'

Un alias de '@page.self': '/blog' también es válido.

Se devolverá una colección vacía si la página no ha sido publicada.

@page.parent - La página padre de una página específica

Este es un caso especial de colección porque siempre devolverá solo el padre de la página actual:

content:
    items:
      '@page.parent': '/blog'

@

Se devolverá una colección vacía si la página está en el nivel superior.

@page.siblings - Hermanos de una página específica

Esta colección recopilará todas las páginas publicadas en el mismo nivel que la página, excluyendo la página misma:

content:
    items:
        '@page.siblings': '/blog'
@page.children - Hijos de una página específica

Esta colección toma una ruta de slug de una página como argumento y devolverá todos los hijos publicados de esa página:

content:
    items:
      '@page.children': '/blog'

Un alias de '@page.pages': '/blog' también es válido. Usar '@page': '/blog' está obsoleto, ya que su significado puede cambiar en el futuro.

@page.modules - Módulos de una página específica

Esta colección toma una ruta de slug de una página como argumento y devolverá todos los módulos publicados de esa página:

content:
    items:
      '@page.modules': '/blog'

Usar el alias de '@page.modular': '/blog' está obsoleto.

@page.all - Hijos y módulos de una página específica

Este método recupera solo los hijos y módulos publicados de la página específica:

content:
    items:
      '@page.all': '/blog'
@page.descendants - Colección de hijos + todos los descendientes de una página específica

Esta colección toma una ruta de slug de una página como argumento y devolverá todos los hijos publicados y todos sus descendientes de esa página:

content:
    items:
      '@page.descendants': '/blog'

Colecciones de Taxonomía

content:
   items:
      '@taxonomy.tag': foo

Usando la opción @taxonomy, puedes utilizar la potente funcionalidad de taxonomía de Grav. Aquí es donde entra en juego la variable taxonomy en el archivo de Configuración del Sitio. Debe haber una definición para la taxonomía definida en ese archivo de configuración para que Grav interprete una referencia de página a ella como válida.

Al establecer @taxonomy.tag: foo, Grav encontrará todas las páginas publicadas en la carpeta /user/pages que tengan tag: foo en su variable de taxonomía:

content:
    items:
       '@taxonomy.tag': [foo, bar]

La variable content.items puede tomar un array de taxonomías y recopilará todas las páginas que cumplan con estas reglas. Las páginas publicadas que tengan ambas etiquetas foo y bar serán recopiladas. El capítulo de Taxonomía cubrirá este concepto con más detalle.

Si deseas colocar múltiples variables en línea, necesitarás separar las subvariables de sus padres con llaves {}. Luego puedes separar las variables individuales en ese nivel con una coma. Por ejemplo: '@taxonomy': {category: [blog, featured], tag: [foo, bar]}. En este ejemplo, las subvariables category y tag se colocan bajo @taxonomy en la jerarquía, cada una con los valores listados dentro de los corchetes []. Las páginas deben cumplir todas estas condiciones para ser encontradas.

Si tienes múltiples variables en un solo padre para establecer, puedes hacerlo usando el método en línea, pero por simplicidad, recomendamos usar el método estándar. Aquí hay un ejemplo:

content:
  items:
    '@taxonomy':
      category: [blog, featured]
      tag: [foo, bar]

Cada nivel en la jerarquía agrega dos espacios en blanco antes de la variable. YAML te permitirá usar tantos espacios como quieras aquí, pero dos es la práctica estándar. En el ejemplo anterior, tanto la variable category como tag están establecidas bajo @taxonomy.

Las colecciones de páginas se filtrarán automáticamente por taxonomía cuando se haya establecido una en la URL (por ejemplo, /archive/category:news). Esto te permite construir una sola plantilla de archivo de blog pero filtrar la colección dinámicamente usando la URL. Si tu colección de páginas debe ignorar la taxonomía establecida en la URL, usa la bandera url_taxonomy_filters:false para deshabilitar esta función.

Colecciones Complejas

También puedes proporcionar múltiples definiciones de colecciones complejas y la colección resultante será la suma de todas las páginas encontradas de cada una de las definiciones de colección. Por ejemplo:

content:
  items:
    - '@self.children'
    - '@taxonomy':
         category: [blog, featured]

Además, puedes filtrar la colección usando filter: type: value. El tipo puede ser cualquiera de los siguientes: published, visible, page, module, routable. Estos corresponden a los métodos específicos de la colección, y puedes usar varios para filtrar tu colección. Todos son true o false. Además, está type que toma un solo nombre de plantilla, types que toma un array de nombres de plantilla, y access que toma un array de niveles de acceso. Por ejemplo:

content:
  items: '@self.siblings'
  filter:
    visible: true
    type: 'blog'
    access: ['site.login']

El tipo también puede ser negativo: non-published, non-visible, non-page (=module), non-module (=page) y non-routable, pero se prefiere si usas la versión positiva con el valor false.

content:
  items: '@self.children'
  filter:
    published: false

Los filtros de colección se han simplificado desde Grav 1.6. Las variantes antiguas modular y non-modular seguirán funcionando, pero no se recomienda su uso. Usa module y page en su lugar.

Opciones de Ordenación

content:
    order:
        by: date
        dir: desc
    limit: 5
    pagination: true

El orden de las subpáginas sigue las mismas reglas que el orden de las carpetas, las opciones disponibles son:

Ordenación Detalles
default El orden se basa en el sistema de archivos, es decir, 01.home antes de 02.advark
title El orden se basa en el título definido en cada página
basename El orden se basa en el nombre de la carpeta alfabético después de haber sido procesado por la función PHP basename()
date El orden se basa en la fecha definida en cada página
modified El orden se basa en la marca de tiempo de modificación de la página
folder El orden se basa en el nombre de la carpeta con cualquier prefijo numérico, es decir, 01., eliminado
header.x El orden se basa en cualquier campo del encabezado de la página. Por ejemplo, header.taxonomy.year. También se puede agregar un valor predeterminado mediante una barra vertical. Por ejemplo, header.taxonomy.year|2015
random El orden es aleatorio
custom El orden se basa en la variable content.order.custom
manual El orden se basa en la variable order_manual. OBSOLETO
sort_flags Permite anular las banderas de ordenación para el orden basado en el encabezado de la página o el orden predeterminado. Si la extensión intl de PHP está cargada, solo están disponibles estas banderas. De lo contrario, puedes usar las banderas de ordenación estándar de PHP.

La variable content.order.dir controla en qué dirección debe ser el orden. Los valores válidos son desc o asc.

content:
    order:
        by: default
        custom:
            - _showcase
            - _highlights
            - _callout
            - _features
    limit: 5
    pagination: true

En la configuración anterior, puedes ver que content.order.custom está definiendo un orden manual personalizado para asegurarse de que la página se construya con la sección showcase primero, la sección highlights segunda, etc. Ten en cuenta que si una página no se especifica en la lista de ordenación personalizada, Grav recurrirá a content.order.by para las páginas no especificadas.

Si una página tiene un slug personalizado, debes usar ese slug en la lista content.order.custom.

La variable content.pagination es una bandera booleana simple para ser usada por plugins, etc., para saber si se debe inicializar la paginación para esta colección. content.limit es el número de elementos mostrados por página cuando la paginación está habilitada.

Rango de Fechas

También existe la capacidad de filtrar páginas por un rango de fechas:

content:
    items: '@self.children'
    dateRange:
        start: 1/1/2014
        end: 1/1/2015

Puedes usar cualquier formato de fecha compatible con strtotime(), como -6 semanas o último lunes, así como fechas más tradicionales como 01/23/2014 o 23 de enero de 2014. El rango de fechas filtrará cualquier página que tenga una fecha fuera del rango de fechas proporcionado. Tanto la fecha de inicio como la de fin son opcionales, pero al menos una debe proporcionarse.

Múltiples Colecciones

Cuando creas una colección con content: items: en tu YAML, estás definiendo una sola colección basada en varias condiciones. Sin embargo, Grav te permite crear un conjunto arbitrario de colecciones por página, solo necesitas crear otra:

content:
    items: '@self.children'
    order:
        by: date
        dir: desc
    limit: 10
    pagination: true

fruit:
    items:
       '@taxonomy.tag': [fruit]

Esto configura 2 colecciones para esta página, la primera usa la colección predeterminada content, pero la segunda define una colección basada en taxonomía llamada fruit. Para acceder a estas dos colecciones a través de Twig, puedes usar la siguiente sintaxis:

{% set default_collection = page.collection %}
{% set fruit_collection = page.collection('fruit') %}

Métodos del Objeto Colección

Los métodos iterables incluyen:

Propiedad Descripción
Collection::append($items) Agrega otra colección o array
Collection::first() Obtiene el primer elemento de la colección
Collection::last() Obtiene el último elemento de la colección
Collection::random($num) Elige $num elementos aleatorios de la colección
Collection::reverse() Invierte el orden de la colección
Collection::shuffle() Aleatoriza toda la colección
Collection::slice($offset, $length) Corta la lista

También tiene varios métodos específicos de la colección útiles:

Propiedad Descripción
Collection::addPage($page) Puedes agregar otra página a esta colección
Collection::copy() Crea una copia de la colección actual
Collection::current() Obtiene el elemento actual en la colección
Collection::key() Devuelve el slug del elemento actual
Collection::remove($path) Elimina una página específica en la colección, o la actual si $path = null
Collection::order($by, $dir, $manual) Ordena la colección actual
Collection::intersect($collection2) Fusiona dos colecciones, manteniendo los elementos que ocurren en ambas colecciones (como una condición "AND")
Collection::merge($collection2) Fusiona dos colecciones, manteniendo los elementos que ocurren en cualquiera de las colecciones (como una condición "OR")
Collection::isFirst($path) Determina si la página identificada por la ruta es la primera
Collection::isLast($path) Determina si la página identificada por la ruta es la última
Collection::prevSibling($path) Devuelve la página hermana anterior si es posible
Collection::nextSibling($path) Devuelve la página hermana siguiente si es posible
Collection::currentPosition($path) Devuelve el índice actual
Collection::dateRange($startDate, $endDate, $field) Filtra la colección actual con fechas
Collection::visible() Filtra la colección actual para incluir solo páginas visibles
Collection::nonVisible() Filtra la colección actual para incluir solo páginas no visibles
Collection::pages() Filtra la colección actual para incluir solo páginas (y no módulos)
Collection::modules() Filtra la colección actual para incluir solo módulos (y no páginas)
Collection::published() Filtra la colección actual para incluir solo páginas publicadas
Collection::nonPublished() Filtra la colección actual para incluir solo páginas no publicadas
Collection::routable() Filtra la colección actual para incluir solo páginas enrutables
Collection::nonRoutable() Filtra la colección actual para incluir solo páginas no enrutables
Collection::ofType($type) Filtra la colección actual para incluir solo páginas donde la plantilla = $type
Collection::ofOneOfTheseTypes($types) Filtra la colección actual para incluir solo páginas donde la plantilla está en el array $types
Collection::ofOneOfTheseAccessLevels($levels) Filtra la colección actual para incluir solo páginas donde el acceso de la página está en el array de $levels

Los siguientes métodos han quedado obsoletos en Grav 1.7: Collection::modular() y Collection::nonModular(). Usa Collection::modules() y Collection::pages() respectivamente.

Aquí hay un ejemplo tomado de la plantilla docs.html.twig del tema Learn2 que define una colección basada en taxonomía (y opcionalmente etiquetas si existen) y usa los métodos Collection::isFirst y Collection::isLast para agregar condicionalmente la navegación de la página:

{% set tags = page.taxonomy.tag %}
{% if tags %}
    {% set progress = page.collection({'items':{'@taxonomy':{'category': 'docs', 'tag': tags}},'order': {'by': 'default', 'dir': 'asc'}}) %}
{% else %}
    {% set progress = page.collection({'items':{'@taxonomy':{'category': 'docs'}},'order': {'by': 'default', 'dir': 'asc'}}) %}
{% endif %}

{% block navigation %}
        <div id="navigation">
        {% if not progress.isFirst(page.path) %}
            <a class="nav nav-prev" href="{{ progress.nextSibling(page.path).url|e }}"> <i class="fa fa-chevron-left"></i></a>
        {% endif %}

        {% if not progress.isLast(page.path) %}
            <a class="nav nav-next" href="{{ progress.prevSibling(page.path).url|e }}"><i class="fa fa-chevron-right"></i></a>
        {% endif %}
        </div>
{% endblock %}

nextSibling() es hacia arriba en la lista y prevSibling() es hacia abajo en la lista, así es como funciona:

Suponiendo que tienes las páginas:

Proyecto A
Proyecto B
Proyecto C

Si estás en el Proyecto A, la página anterior es el Proyecto B. Si estás en el Proyecto B, la página anterior es el Proyecto C y la siguiente es el Proyecto A

Colecciones Programáticas

Puedes tomar el control total de las colecciones directamente desde PHP en plugins de Grav, temas, o incluso desde Twig. Este es un enfoque más codificado en comparación con definirlas en el frontmatter de tu página, pero también permite una lógica de colecciones más compleja y flexible.

Colecciones en PHP

Puedes realizar lógica avanzada de colecciones con PHP, por ejemplo:

$collection = new Collection($pages);
$collection->setParams(['taxonomies' => ['tag' => ['dog', 'cat']]])->dateRange('01/01/2016', '12/31/2016')->published()->ofType('blog-item')->order('date', 'desc');

$titles = [];

foreach ($collection as $page) {
    $titles[] = $page->title();
}

La función order() también puede, además de los parámetros by y dir, tomar un parámetro manual y sort_flags. Estos están documentados arriba. También puedes usar el mismo método evaluate() que usan las colecciones de páginas basadas en frontmatter:

$page = Grav::instance()['page'];
$collection = $page->evaluate(['@page.children' => '/blog', '@taxonomy.tag' => 'photography']);
$ordered_collection = $collection->order('date', 'desc');

Y otro ejemplo de ordenación personalizada sería:

$ordered_collection = $collection->order('header.price','asc',null,SORT_NUMERIC);

También puedes hacer algo similar directamente en Plantillas Twig:

{% set collection = page.evaluate([{'@page.children':'/blog', '@taxonomy.tag':'photography'}]) %}
{% set ordered_collection = collection.order('date','desc') %}

Colecciones Avanzadas

Por defecto, cuando llamas a page.collection() en el Twig de una página que tiene una colección definida en el encabezado, Grav busca una colección llamada content. Esto permite la capacidad de definir múltiples colecciones, pero puedes llevar esto un paso más allá.

Si necesitas generar una colección programáticamente, puedes hacerlo llamando a page.collection() y pasando un array en el mismo formato que la definición de colección del encabezado de la página. Por ejemplo:

{% set options = { items: {'@page.children': '/my/pages'}, 'limit': 5, 'order': {'by': 'date', 'dir': 'desc'}, 'pagination': true } %}
{% set my_collection = page.collection(options) %}

<ul>
{% for p in my_collection %}
<li>{{ p.title|e }}</li>
{% endfor %}
</ul>

Generando un menú para todo el sitio (necesitas establecer la propiedad menu en el frontmatter de la página):

---
title: Inicio
menu: Inicio
---
{% set options = { items: {'@root.descendants':''}, 'order': {'by': 'folder', 'dir': 'asc'}} %}
{% set my_collection = page.collection(options) %}

{% for p in my_collection %}
{% if p.header.menu %}
    <ul>
    {% if page.slug == p.slug %}
        <li class="{{ p.slug|e }} active"><span>{{ p.menu|e }}</span></li>
    {% else %}
        <li class="{{ p.slug|e }}"><a href="{{ p.url|e }}">{{ p.menu|e }}</a></li>
    {% endif %}
    </ul>
{% endif %}
{% endfor %}

Paginación con Colecciones Avanzadas

Una pregunta común que escuchamos es cómo habilitar la paginación para colecciones personalizadas. La paginación es un plugin que se puede instalar a través de GPM con el nombre pagination. Una vez instalado, funciona "fuera de la caja" con colecciones configuradas en la página, pero no sabe nada sobre colecciones personalizadas creadas en Twig. Para facilitar este proceso, la paginación viene con su propia función Twig llamada paginate() que proporcionará la funcionalidad de paginación que necesitamos.

Después de pasar la colección y el límite a la función paginate(), también necesitamos pasar la información de paginación directamente a la plantilla partials/pagination.html.twig para que se renderice correctamente.

{% set options = { items: {'@root.descendants':''}, 'order': {'by': 'folder', 'dir': 'asc'}} %}
{% set my_collection = page.collection(options) %}
{% do paginate( my_collection, 5 ) %}

{% for p in my_collection %}
    <ul>
        {% if page.slug == p.slug %}
            <li class="{{ p.slug|e }} active"><span>{{ p.menu|e }}</span></li>
        {% else %}
            <li class="{{ p.slug|e }}"><a href="{{ p.url|e }}">{{ p.menu|e }}</a></li>
        {% endif %}
    </ul>
{% endfor %}

{% include 'partials/pagination.html.twig' with {'base_url':page.url, 'pagination':my_collection.params.pagination} %}

Manejo Personalizado de Colecciones con el Evento onCollectionProcessed()

Hay momentos en que las opciones de eventos simplemente no son suficientes. Momentos en los que deseas obtener una colección pero luego manipularla aún más basándote en algo muy personalizado. Imagina, por ejemplo, un caso de uso en el que tienes lo que parece ser una lista de blog bastante estándar, pero tu cliente quiere tener un control detallado sobre lo que se muestra en la lista. Quiere tener un interruptor personalizado en cada elemento del blog que le permita eliminarlo de la lista, pero aún así tenerlo publicado y disponible a través de un enlace directo.

Para hacer esto posible, simplemente podemos agregar una opción personalizada display_in_listing: false en el encabezado de la página para el elemento:

---
title: 'Mi Historia'
date: '13:34 04/14/2020'
taxonomy:
    tag:
        - journal
display_in_listing: false
---
...

El problema es que no hay forma de definir o incluir este filtro al definir una colección en la página de listado. Probablemente esté definida de la siguiente manera:

---
menu: Noticias
title: 'Mi Blog'
content:
    items:
        - self@.children
    order:
        by: date
        dir: desc
    limit: 8
    pagination: true
    url_taxonomy_filters: true
---
...

Entonces, la colección simplemente está definida por la directiva self@.children para obtener todos los hijos publicados de la página actual. ¿Qué pasa con esas páginas que tienen display_in_listing: false establecido? Necesitamos hacer un trabajo adicional en esa colección antes de que se devuelva para asegurarnos de eliminar cualquier elemento que no queremos ver. Para hacer esto, podemos usar el evento onCollectionProcessed() en un plugin personalizado. Necesitamos agregar el listener:

public static function getSubscribedEvents(): array
    {
        return [
            ['autoload', 100000],
            'onPluginsInitialized' => ['onPluginsInitialized', 0],
            'onCollectionProcessed' => ['onCollectionProcessed', 10]
        ];
    }

Luego, necesitamos definir el método y recorrer los elementos de la colección, buscando cualquier página con ese campo display_in_listing: establecido, luego eliminarla si es false:

/**
     * Elimina cualquier página de la colección con display_in_listing: false|0
     *
     * @param Event $event
     */
    public function onCollectionProcessed(Event $event): void
    {
        /** @var Collection $collection */
        $collection = $event['collection'];

        foreach ($collection as $item) {
            $display_in_listing = $item->header()->display_in_listing ?? true;
            if ((bool) $display_in_listing === false) {
                $collection->remove($item->path());
            }
        }

    }

Ahora tu colección tiene los elementos correctos, y todos los demás plugins o plantillas Twig que dependen de esa colección verán esta colección modificada, por lo que cosas como la paginación funcionarán como se espera.