Patrick Fiedorowicz |  24.08.2016 | TYPO3, Extensions

Nachdem ich bisher viel positives Feedback für mein TypoScript-CATMENU für tt_news bekommen habe, ist es nun Zeit geworden, einen Nachfolger für tx_news auf die Beine zu stellen. Natürlich auch wieder mit News-Counter pro Kategorie.

tt_news ist tot, lange lebe tx_news. Ganz so dramatisch ist es nicht, aber tt_news verliert mehr und mehr Bedeutung zugunsten von tx_news. Vor einiger Zeit habe ich hier ein flexibles Kategorie-Menü mit News-Counter für tt_news erstellt und dafür sehr viel Lob bekommen. Nachdem ich aber in meiner eigenen Website und in sämtlichen Kundenprojekten nur noch tx_news einsetze, ist es notwendig geworden, eine neue, angepasste Version zu erstellen, welche die gleichen Features bietet.

Für diejenigen, welche mein CATMENU noch nicht kennen sollten, hier nochmal kurz die Features:

  • maximale Flexibilität durch Verwendung von reinem TypoScript
  • Auflistung aller News-Kategorien, auch über mehrere Ebenen
  • Zählung aller zugewiesenen News pro Kategorie
  • Links zum Filtern nach Kategorien

Ich habe wieder bewusst darauf geachtet, möglichst viele Kommentar zu hinterlegen, so dass auch TYPO3-Anfänger wenig Probleme haben sollten, die Zusammenhänge zu verstehen.

# zu erst der Marker für das neue Kat-Menu
lib.catList = COA
lib.catList {
  # hole alle Hauptkategorien
  10 = CONTENT
  10 {
    # wrappe die gesamte Liste als "unsortierte Liste"
    wrap = <ul class="news-catmenu">|</ul>
    table = sys_category
    select {
      # hier muss die pid eures News-Sysordners rein, bzw. wo die News-Kategorien gespeichert sind
      pidInList = 3
      orderBy = title
      where = parent=0 AND deleted=0 AND hidden=0
    }
    renderObj = COA
    renderObj {
      # wrappe jede gefundene Hauptkategorie als Listenelement
      wrap = <li>|</li>
      # überschreibe den vorherigen Wrap ...
      wrap.override = <li class="active">|</li>
      # ... nur, wenn ...
      wrap.override.if {
        # ... eine News-Kategorie bereits ausgewählt wurde und per GET/POST ermittelt werden kann
        value.data = GP:tx_news_pi1|overwriteDemand|categories
        # und dieser ermittelte Wert der aktuellen uid gleicht
        equals.field = uid        
      }
      # zeig mir den Kategorie-Titel und mache einen Filter-Link daraus
      10 = TEXT
      10 {
        # das title-Feld soll als Text angezeigt werden (könnte man auch description... verwenden)
        field = title
        typolink {
          # verlinke zu der Seite mit der News-Auflistung (Listenansicht)
          parameter = 34
          title.field = title
          # füge den GET-Parameter für die ausgewählte Kategorie hinzu
          additionalParams.dataWrap = &tx_news_pi1[overwriteDemand][categories]={field:uid}
          # cHash mit übergeben fürs Caching
          useCacheHash = 1
        }
      }
      # zeig mir einen Counter aller News-Einträge in dieser Kategorie
      20 = CONTENT
      20 {
        table = sys_category
        select {
          # hier wieder der Sysordner aller News-Einträge und -Kategorien
          pidInList = 3
          join (
            sys_category_record_mm ON (sys_category.uid = sys_category_record_mm.uid_local)
              JOIN tx_news_domain_model_news ON (tx_news_domain_model_news.uid = sys_category_record_mm.uid_foreign)
          )
          andWhere.dataWrap (
            (sys_category.uid={field:uid}) 
              AND tx_news_domain_model_news.deleted=0 AND tx_news_domain_model_news.hidden=0
              AND sys_language_uid={TSFE:sys_language_uid}
          )
          # führe einen count durch und speichere das Ergebnis in "counter"
          selectFields = count(*) AS counter
        }
        renderObj = TEXT
        renderObj {
          # zeig mir nun das Ergebnis des Counters an und wrappe es
          field = counter
          wrap =  <span>(|)</span>
        }
      }
      # zeig mir alle Unterkategorien der aktuellen Kategorie an
      30 = CONTENT
      30 {
        stdWrap {
          # führe den Abschnitt nur aus, wenn in der Select-Abfrage ein Wert gefunden wurde
          required = 1
          wrap = <ul>|</ul>
        }
        table = sys_category
        select {
          pidInList = 3
          orderBy = title
          andWhere.dataWrap = parent={field:uid} AND deleted=0 AND hidden=0
        }
        # vererbe die Einstellungen von lib.CatList.10.renderObj an dieses renderObj
        renderObj < lib.catList.10.renderObj
        renderObj = COA
        renderObj {
          # zeige den Titel mit Verlinkung an, genauso wie bei lib.catList.10.renderObj.10 (vererbt)
          10 < lib.catList.10.renderObj.10
          # zeige den News-Counter an, genauso wie bei lib.catList.10.renderObj.20 (vererbt)
          20 < lib.catList.10.renderObj.20
          # zeige die Unterkategorien an, genauso wie bei lib.catList.10.renderObj.30 (vererbt)
          30 < lib.catList.10.renderObj.30
          # wenn noch eine 4. und 5. Kategorien-Ebene abgebildet werden sollen,
          # dann die folgenden 6 Zeilen verwenden
          # 30.renderObj = COA
          # 30.renderObj {
          #   10 < lib.catList.10.renderObj.10
          #   20 < lib.catList.10.renderObj.20
          #   30 < lib.catList.10.renderObj.30
          # }
        }
      }
    }
  }
}

Wie schaut das nun in Aktion aus? Hier im Kategorie-Menü auf der Seite "News" könnt ihr es euch in der rechten Sidebar ansehen. Ansonsten wünsche ich allen viel Spaß damit und bin wie immer offen für Feedback :)

zurück zu allen News

Kommentare

  1. Georg TheissGeorg Theiss 23.10.2016
    einfach mal ein grosses Dankeschön, vor allem für die sauber Kommentierung!

    Es wird bei mir der Einfachheit halber mit einem DCE-Modul zur Kategorieauswahl zum Einsatz kommen (http://aikantink.de/y4y/blog-aktuelles-snippets/blog-detailansicht/news/fiedomedia-catmenu-fuer-tx-news-mit-counter-in-dce-mit-kategorieauswahl/
  2. Hannes LangHannes Lang 17.12.2016
    bei mehrsprachiger Version wird je Sprache eine Zeile ausgegeben. Gibts da einen Trick?
    1. Hannes LangHannes Lang 17.12.2016
      .... gefunden: in erster Frage fehlt: languageField = sys_language_uid
  3. Jari-Hermann ErnstJari-Hermann Ernst 24.02.2017
    Danke für dieses wirklich gut kommentierte TypoScript-Beispiel. Das war genau das, was ich gerade gesucht habe!

    Allerdings wird bei mir der span mit dem Counter für die News nicht im a-Tag generiert, sondern dahinter. Auf Deiner Beispielseite ist das anders.

    Auf was muss ich da achten?
    1. Patrick FiedorowiczPatrick Fiedorowicz 25.02.2017
      Hallo Jari-Hermann,

      danke für das Lob :)

      Du hast recht, ich hab es in der Version auf meiner Website etwas umgebaut. Im Grunde ist das aber nicht viel komplizierter:
      Mach aus dem 10 = TEXT (Kategorie-Titel) ein COA und pack die 20 = Content (Counter) mit rein. Anschließend machst du für das gesamte, neu erstellte COA ein stdWrap.typolink (was vorher beim Kategorie-Titel war). Fertig.

      Schöne Grüße
      Patrick
  4. Alex MöllerAlex Möller 23.04.2017
    Hallo, verwende Typo3 V8 habe gerade den script probiert. bekomme aber immer folgende url:

    meineDomain.de/news/?tx_news_pi1%5BoverwriteDemand%5D%5Bcategories%5D=12&cHash=085fffec7addb1c707d87a812eda03bf

    obwohl ich Realurl verwende!
    Sollte ich in der Realurl_config noch was eintragen?

    LG Alex
    1. Patrick FiedorowiczPatrick Fiedorowicz 23.04.2017
      Hi Alex,

      du hast recht, dir fehlt die RealUrl-Konfig für die News-Kategorien.
      Funktionieren denn die News-Detail-Links mit RealUrl?
      Hast du Autoconfig in RealUrl aktiviert oder konfigurierst du das selbst?

      Hier meine Konfig für TYPO3 7, das kannst du gerne verwenden und auf TYPO3 8 umbauen:
      'postVarSets' => array(
      '_DEFAULT' => array(
      'kategorie' => array(
      array(
      'GETvar' => 'tx_news_pi1[overwriteDemand][categories]',
      'lookUpTable' => array(
      'table' => 'sys_category',
      'id_field' => 'uid',
      'alias_field' => 'title',
      'addWhereClause' => ' AND NOT deleted',
      'useUniqueCache' => 1,
      'useUniqueCache_conf' => array(
      'strtolower' => 1,
      'spaceCharacter' => '-',
      ),
      ),
      ),
      ),
      ),
      ),
      (Sorry für die schlechte Formatierung)

      Grüße Patrick
  5. StefanieStefanie 26.04.2017
    Hallo,
    danke für das Script - genau das, was ich gesucht habe!
    Allerdings habe ich eine mehrsprachige Website und der Counter funktioniert nicht korrekt. Er zählt alle vorhandenen/übersetzten Artikel unabhängig von der Sprache:

    select {
    # hier wieder der Sysordner aller News-Eintraege und -Kategorien
    pidInList = 14
    join = sys_category_record_mm ON (sys_category.uid = sys_category_record_mm.uid_local)
    JOIN tx_news_domain_model_news ON (tx_news_domain_model_news.uid = sys_category_record_mm.uid_foreign)
    andWhere.dataWrap = (sys_category.uid={field:uid})
    AND tx_news_domain_model_news.deleted=0 AND tx_news_domain_model_news.hidden=0
    AND sys_language_uid={TSFE:sys_language_uid}
    languageField = sys_language_uid
    # fuehre einen count durch und speichere das Ergebnis in "counter"
    selectFields = count(*) AS counter
    }

    Hast du eine Idee, woran das liegen könnte?

    Danke und Grüße,
    Stefanie
    1. Patrick FiedorowiczPatrick Fiedorowicz 26.04.2017
      Hi Stefanie,

      versuch mal das andWhere.dataWrap ohne Umbrüche zu schreiben:
      andWhere.dataWrap = (sys_category.uid={field:uid}) AND tx_news_domain_model_news.deleted=0 AND tx_news_domain_model_news.hidden=0 AND sys_language_uid={TSFE:sys_language_uid}

      Grüße Patrick
    2. StefanieStefanie 26.04.2017
      Danke für den Tipp - wenn nur alles so einfach wäre ;-)
      Allerdings war dann die sys_language_uid noch mehrdeutig und musste speziell der news-Tabelle zugewiesen werden:

      andWhere.dataWrap = (sys_category.uid={field:uid}) AND tx_news_domain_model_news.deleted=0 AND tx_news_domain_model_news.hidden=0 AND tx_news_domain_model_news.sys_language_uid={TSFE:sys_language_uid}

      Jetzt stimmen die Zahlen!

      Grüße Stefanie
  6. Kurt KunigKurt Kunig 11.05.2017
    Ich habe Deine lib.catList von oben übernommen. Bei mir wird aber nur die Parent-Kategorie angezeigt. Die Unterkategorien bleiben außen vor?
    Bei einem Artikel setze ich immer nur die Subkategorie ohne die Parent-Cat. zusätzlich zu setzen.
    Hast Du eine Idee, woran das liegen kann?
    Ich habe TYPO3 V8.7 und news 5.3.2 im Einsatz.
  7. Markus DübbertMarkus Dübbert 19.06.2017
    Das Menu funktioniert nicht in TYPO3 8.7.1 (news 6.0.0)
    In 7.6.18 mit news 5.3.3 oder auch news 6.0.0 funktioniert es.

    Mir ist noch nicht ganz klar, warum es nicht geht. Die Zuordnung der Unterkategorien funktioniert nicht. Die Unterkategorien (und die Hauptkategorien) werden bei mir bei jeder Hauptkategorie wiederholt.
    1. Markus DübbertMarkus Dübbert 19.06.2017
      Für TYPO3 8.7.1 geht:
      where.dataWrap = parent={field:uid} AND deleted=0 AND hidden=0
      statt
      andWhere.dataWrap = parent={field:uid} AND deleted=0 AND hidden=0
  8. NorbertNorbert 02.08.2017
    Hallo, wirklichein super Skript, vielen Dank dafür.
    Ein Problem hab ich leider dennoch und komme nicht auf die Lösung.
    Ich habe nur den Counter verwendet um Anzahl der Artikel aus einer einzigen Kategorie aus zu geben. Der Counter zählt leider sämtliche Artikel der betreffenden Kategorie (ohne berücksichtigung der Sprache) und ich wollte die Datenbankabfrage noch um "starttime kleiner jetzt" und "endtime größer jetzt" erweitern.
    Eigentlich ganz einfach, aber ich komme einfach nicht auf die Lösung. Könnten Sie mir da kurz weiter helfen? Wär echt super :)

    Vielen Dank
    1. Patrick FiedorowiczPatrick Fiedorowicz 02.08.2017
      Hallo Norbert,

      vielen Dank für dein Lob.

      Achte bitte darauf, dass du join und andWhere in dem Abschnitt für den Counter in eine Zeile schreibst.
      Und dann fügst du am Ende bei andWhere noch hinzu:
      AND tx_news_domain_model_news.starttime < FROM_UNIXTIME() AND tx_news_domain_model_news.endtime > FROM_UNIXTIME()

      Schöne Grüße
      Patrick
    2. NorbertNorbert 02.08.2017
      Guten Tag Patrick,

      leider hatte ich da bereits alles versucht (auch die von Ihnen vorgeschlagenen Änderungen). Sobald ich die mache, liefert mir der Counter jedoch leider gar kein Ergebnis, obwohl jedoch ein Artikel der Abfrage entsprechen würde.
      (der gesamte join steht in einer einzigen langen Zeile)

      Vielen Dank für Ihre Hilfe
    3. NorbertNorbert 03.08.2017
      Hallo Patrick,
      wollte nur bescheid geben dass es jetzt läuft. PERFEKT.
      Mein Fehler war sowohl den join als auch andWhere alles zusammen in eine Zeile. Das darf nicht sein (muss man also in 2 Zeilen schreiben).
      Vielen Dank für deine Hilfe
  9. AndyAndy 02.03.2018
    Hallo und erst Mal ein Lob für das tolle Script.

    Leider scheint es mit TYPO3 8.7 und news 6.3 nicht korrekt zu zählen.
    Es zählt alle News anstatt nur die in der jeweiligen Kategorie.
    Unterkategorien werden keine verwendet.

    Kann da jemand weiterhelfen?

    ...
    # zeig mir den Kategorie-Titel und mache einen Filter-Link daraus
    10 = COA
    10 {
    10 =TEXT
    10 {
    # das title-Feld soll als Text angezeigt werden (koennte man auch description... verwenden)
    field = title
    typolink {
    # verlinke zu der Seite mit der News-Auflistung (Listenansicht)
    parameter = {$news.aktuell.listid}
    title.field = title
    # fuege den GET-Parameter fuer die ausgewaehlte Kategorie hinzu
    additionalParams.dataWrap = &tx_news_pi1[overwriteDemand][categories]={field:uid}
    # cHash mit uebergeben fuers Caching
    useCacheHash = 1
    }
    }
    # zeig mir einen Counter aller News-Eintraege in dieser Kategorie
    20 = CONTENT
    20 {
    table = sys_category
    select {
    # hier wieder der Sysordner aller News-Eintraege und -Kategorien
    pidInList = {$news.aktuell.pid}
    join = sys_category_record_mm ON (sys_category.uid = sys_category_record_mm.uid_local)
    JOIN = tx_news_domain_model_news ON (tx_news_domain_model_news.uid = sys_category_record_mm.uid_foreign)
    andWhere.dataWrap = (sys_category.uid={field:uid}) AND tx_news_domain_model_news.deleted=0 AND tx_news_domain_model_news.hidden=0 AND tx_news_domain_model_news.sys_language_uid={TSFE:sys_language_uid}
    # fuehre einen count durch und speichere das Ergebnis in "counter"
    selectFields = count(*) AS counter
    }
    renderObj = TEXT
    renderObj {
    # zeig mir nun das Ergebnis des Counters an und wrappe es
    field = counter
    wrap = <span>(|)</span>
    }
    }
    }
    # wrap= |
    stdWrap.typolink = <li>|</li>
    ...
    1. Patrick FiedorowiczPatrick Fiedorowicz 03.03.2018
      Hi Andy,

      danke für das Lob :)

      Die Werte hinter join = ... und andWhere.dataWrap = ... müssen in einer Zeile stehen, oder du verwendest die Klammerschreibweise. Ich hab das in meinem Script mal ausgebessert, schaus dir einfach nochmal an.
      (Ich hatte es bisher zur besseren Lesbarkeit auf mehrere Zeilen aufgeteilt...)

      Schöne Grüße
      Patrick
  10. Ulrich DiehlUlrich Diehl 12.07.2019
    Hallo,
    genau das Menü kann ich gut gebrauchen, habe aber auch das Problem, dass die Zeile im Bereich Counter mit dem "andWhere.dataWrap" scheinbar komplett ignoriert wird:, meine Version: TYPO3 8.7.27, News7.20:

    20 = CONTENT
    20 {
    table = sys_category
    select {
    # hier wieder der Sysordner aller News-Einträge und -Kategorien
    pidInList = XXX
    join = sys_category_record_mm ON (sys_category.uid = sys_category_record_mm.uid_local) JOIN tx_news_domain_model_news ON (tx_news_domain_model_news.uid = sys_category_record_mm.uid_foreign)
    andwhere.dataWrap = (sys_category.uid={field:uid}) AND tx_news_domain_model_news.deleted=0 AND tx_news_domain_model_news.hidden=0 AND sys_language_uid={TSFE:sys_language_uid}
    # führe einen count durch und speichere das Ergebnis in "counter"
    selectFields = count(*) AS counter
    }
    renderObj = TEXT
    renderObj {
    # zeig mir nun das Ergebnis des Counters an und wrappe es
    field = counter
    wrap = <span>(|)</span>
    }
    }

    "join" steht in einer Zeile, in der nächsten dann "andWhere.dataWrap". Wenn ich die Zeile mit "andWhere" auskommentiere, ändert sich nix.

    Ansonsten: Großes Lob!
    1. Ulrich DiehlUlrich Diehl 15.07.2019
      Also, "andWhere" ist seit Version 7.1 deprecated:
      "Note: This property is deprecated since TYPO3 7.1! Use the properties .where and .markers instead."
      So steht es in der Doku, jetzt müsste ich nur noch wissen, wie es stattdessen funktioniert ;)
    2. Patrick FiedorowiczPatrick Fiedorowicz 15.07.2019
      Hi Ulrich,

      wenn du statt "andWhere" nur "where" verwendest, könnte es funktionieren.
      Kannst du das prüfen? Wenn es funktioniert, dann aktualisiere ich meine Anleitung.

      Grüße Patrick
  11. Ulrich DiehlUlrich Diehl 16.07.2019
    Aah, das hatte ich schon probiert, da ich aber noch einen Schreibfehler drin hatte, gab es nur eine Fehlermeldung... Kaum macht man es richtig, schon funktioniert es – fast! Leider wirft mir der Counter falsche Zahlen aus, ich vermute mal, das in der Datenbank noch veraltete Relationen dazu führen, oder hast du eine andere Idee, Patrick?
  12. Ulrich DiehlUlrich Diehl 16.07.2019
    Also, die Datenbank ist bereinigt, jetzt stimmt alles "where" statt "andWhere" ist dann ab TYPO3 8LTS die Lösung, vielen Dank!
  13. Andrey SAndrey S 12.02.2020
    Ich habe den Code in Typo3 9.5.11 ausprobiert.
    Es funktioniert, der Counter gibt aber für jede Kategorie immer die Gesamtzahl von Nachrichten.
    Was kann ich machen?
    Danke!
    1. Patrick FiedorowiczPatrick Fiedorowicz 12.02.2020
      Hi Andrey,

      ich hab den Code für TYPO3 9 und aufwärts etwas angepasst. Du musst andWhere durch where (kommt 2x vor) im TypoScript ersetzen, dann sollte es funktionieren.

      Grüße Patrick

Neuer Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Bitte gib Sie an, um dein Gravatar-Bild anzuzeigen.