Veranstaltungen nach Monaten sortiert ausgeben mit der TYPO3 Extension news

Termine (Veranstaltungen) sollen in Monatsabfolge angezeigt werden. Jeder Monat, in dem mindestens eine Veranstaltung stattfindet, soll samt Jahresanzeige als Überschrift über den zugehörigen Terminen erscheinen. Nach Ende des Termins soll die Anzeige verschwinden und, sofern keine weiteren Termine in diesem Monat stattfinden, auch die Überschrift.

Verwendet wird die TYPO3 Extension news. Eventuell kann zusätzlich die Extension eventnews verwendet werden, wenn man weitere Felder, wie z.B. das Ende eines mehrtägigen Termins, benötigt. Man kann die fehlenden Felder aber auch mit einer eigenen Extension hinzufügen.
Den Ausgabemodus des news Plugins stellt man auf Datumsmenü [News->dateMenu], die Sortierung auf aufsteigend [asc], das zu benutzende Datumsfeld auf Angegebenes Datum/Uhrzeit [datetime]. Als Zeitlimit kann -1 day verwendet werden, wenn die Termine eine durchschnittliche Dauer von 2 oder 3 Tagen haben. Man kann statt dessen aber auch ein Stopdatum für die jeweilige News verwenden (s.u.).

Man holt sich nun das dateMenu Template aus der news Extension (typo3conf/ext/news/Resources/Private/Templates/News/DateMenu.html), legt es in sein sitepackage und macht es im Typoscript bekannt:

[page["uid"] == (100)]
plugin.tx_news.view.templateRootPaths.10 = EXT:my_sitepackage/Resources/Private/Extensions/Newsevents/Templates/
[END]

Die Condition – hier für die Seitenid 100 und in der Syntax für TYPO3 > 9.4 – benötigt man natürlich nur, wenn man außerdem noch weitere, „normale“ News einsetzt.

Das DateMenu.html wird bearbeitet und sieht dann folgendermaßen aus:

<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
<f:layout name="General" />
<!--
	=====================
		Templates/News/DateMenu.html
-->
<f:section name="content">
    <div class="newsevents-menu-view">
        <f:for each="{data.single}" key="year" as="months">
            <f:for each="{months}" key="month" as="count">
                <div class="month">
                    <span>
                        <f:translate key="LLL:EXT:my_sitepackage/Resources/Private/Language/locallang.xlf:newsevent.{month}" />
                        {year}
                    </span>
                </div>
                <f:for each="{news}" as="newsItem" iteration="iterator">
                    <f:if condition="{year} == <f:format.date format='Y'>{newsItem.datetime}</f:format.date> && {month} == <f:format.date format='m'>{newsItem.datetime}</f:format.date>">
                        <f:render partial="List/Item" arguments="{newsItem: newsItem,settings:settings,iterator:iterator}" />
                    </f:if>
                </f:for>
            </f:for>
        </f:for>
    </div>
</f:section>

Das – gewollte und hübsche – Ergebnis ist, dass der jeweilige Monat ausgeschrieben, das Jahr angehängt, beides in einem span gewrapt und alles zusammen in einem div ausgegeben wird. Danach wird die Listendarstellung der News für diesen Monat ausgegeben – wir befinden uns ja in der for-Schleife des Monats – und die Zuordnung der News zum jeweiligen Monat geschieht über die vorangestellte condition (bei der auch das Jahr berücksichtigt werden muss, damit der Code auch für einen längeren Zeitraum als 11 Monate in der Zukunft funktioniert).

Selbstverständlich benötigt man noch die angegebene XLF Datei für die – ggfls. mehrsprachige – Ausgabe des Monats.
An dieser Stelle ein Dank an @foodfindr. Diese Zeile:

<div class="month">
    <span>
        <f:translate key="LLL:EXT:my_sitepackage/Resources/Private/Language/locallang.xlf:newsevent.{month}" /> 
        {year}
    </span>
</div>

erspart eine ursprünglich von mir vorgesehene Abfrage auf jeden Monat:

<div class="month">
    <f:if condition="{0: '{month}'} == {0: '01'}">
        <span>
            <f:translate key="LLL:EXT:my_sitepackage/Resources/Private/Language/locallang.xlf:newsevent.january" />
    </f:if>
    <f:if condition="{0: '{month}'} == {0: '02'}">
        <span>
            <f:translate key="LLL:EXT:my_sitepackage/Resources/Private/Language/locallang.xlf:newsevent.february" />
    </f:if>
    ...
    {year}</span>
</div>

Die Condition, wenn man sie verwenden möchte, könnte auch so aussehen (TYPO3 > 8.7)

<f:if condition="{month} == '01'">
...

Danke für diesen Hinweis an @lorenzulrich.

So sieht dann die XLF Datei aus:

<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<?xml version="1.0" encoding="UTF-8"?>
<xliff version="1.0" xmlns="urn:oasis:names:tc:xliff:document:1.1">
   <file source-language="de" datatype="plaintext" original="messages" date="2019-09-26T18:20:51Z" product-name="my-ext">
       <header/>
       <body>
           <trans-unit id="newsevent.01">
               <source>Januar</source>
           </trans-unit>
           ...
           <trans-unit id="newsevent.12">
               <source>Dezember</source>
           </trans-unit>
       </body>
   </file>
</xliff>

Damit die News samt Monatsanzeige nach deren Ende nicht mehr angezeigt wird, kann man, wie oben bereits erläutert, ein Stopdatum setzen oder das Zeitlimit des Plugin-Datensatzes entsprechend einstellen.