toscho.design

WordPress: Alle Artikel auflisten

WordPress AAA

Vielleicht habe ich mehr Nutzen aus dieser Seite gezogen als meine Leser: Alle Artikel auf einen Blick – das finde ich immer wieder hilfreich, wenn ich mal an meine interne Verlinkung denke.

Und so geht es:

  • Wir legen eine neue PHP-Datei ins Templateverzeichnis und nennen sie ›_all_files.php‹.
  • Dann besorgen wir uns das praktische Skript sorttable.
  • Und zuletzt brauchen wir noch die Funktion end_on_word().
  • Auswahl der Vorlage ›Alle Artikel‹Jetzt legen wir im Backend eine neue Seite an und wählen als Vorlage ›Alle Artikel‹ aus. Ein bißchen Text hinschreiben, veröffentlichen. Fertig.
<?php
/* Template Name: Alle Artikel
 *
 * Onlinebeispiel: http://toscho.de/uebersicht/alle-artikel/
 * Diese Seite als ›_all_files.php‹ im Themeverzeichnis speichern und beim
 * Erstellen einer neuen Seite als Vorlage verwenden.
 */
get_header();

// Text über der Tabelle. Inhalt einer normalen Seite (Page).
if ( have_posts() )
{
    while ( have_posts() )
    {
        the_post();
        the_title('<h1>', '</h1>');
        the_content('<p><strong>Weiterlesen …</strong></p>');
        link_pages('<p><strong>Seiten:</strong> ', '</p>', 'number');
        edit_post_link('Beitrag bearbeiten', '<p>', '</p>');
    }
}

/**
 * @var object $myQuery Liste aller Artikel.
 */
$myQuery = new WP_Query(
    array(
        'nopaging'    => true,
        'post_type'   => 'post',
        'post_status' => 'publish'
    )
);

if ( $myQuery->have_posts() )
{
?>
<table id="allposts" class="sortable">
  <thead>
    <tr>
      <th scope="col">Titel</th>
      <th scope="col">Datum</th>
      <th scope="col">Kommentare</th>
    </tr>
  </thead>
  <tbody>
<?php
    while ( $myQuery->have_posts() )
    {
        $post = $myQuery->next_post();
?>
    <tr>
      <td><a href="<?php the_permalink(); ?>" title="<?php
        if ( !empty($post->post_excerpt) )
        {
            $_my_excerpt = $post->post_excerpt;
            // Für Browser, die keinen Umbruch im Tooltip zeigen:
            $_my_excerpt = str_replace("\r\n", " \r\n ", $_my_excerpt);
            $_my_excerpt = strip_tags($_my_excerpt);
            $_my_excerpt = htmlspecialchars($_my_excerpt, ENT_QUOTES);
        }
        else
        {
            $_my_excerpt = substr( $post->post_content, 0, 100);
            $_my_excerpt = str_replace("\r\n", " \r\n ", $_my_excerpt);
            $_my_excerpt = strip_tags($_my_excerpt);
            $_my_excerpt = htmlspecialchars($_my_excerpt, ENT_QUOTES);
// ANPASSEN!
            // @see http://toscho.de/2009/php-funktion-end_on_word/
            $_my_excerpt = XWP::end_on_word($_my_excerpt) . '&#160;…';
        }
        echo $_my_excerpt;
        ?>"><?php
        the_title();
        ?></a>
        </td>
        <td sorttable_customkey="<?php
        // YYYYMMDDHHMMSS - damit das Javascript nach Datum sortieren kann.
        echo str_replace(array('-', ' ', ':'), '', $post->post_date);
        ?>"><?php
        the_time('d.m.Y');
        ?></td>
        <td><?php
        if ( 'open' == $post->comment_status && 0 < $post->comment_count )
        {
        /**
         * Das Title-Attribut hilft den Nutzern von Screenreadern, gleich-
         * lautende Links (mit nur einer Zahl als Text) zu unterscheiden. */
            echo '<a href="' . get_permalink() . '#comments"'
            . ' title="Kommentiere ›' . $post->post_title . '‹">'
            . $post->comment_count . '</a>';
        }
        else
        {
        /* Leere Zellen werden sonst anders dargestellt, und per CSS
         * läßt sich das nicht sehr zuverlässig reparieren. */
            echo '&#160;';
        }
        ?>
      </td>
    </tr>
<?php
    }
?>
  </tbody>
</table>
<?php
}
else
{// == !$myQuery->have_posts()
    ?><p>Irgendwas läuft gerade entsetzlich schief …</p><?
}
rewind_posts();

// ANPASSEN!
?>
<script src="http://js.toscho.de/sorttable.js" type="text/javascript"></script>
<?php
get_footer();

CSS

Das Auge sortiert mit; also habe ich noch ein, zwei Regeln ins Stylesheet gehämmert:

table
    {
        margin:             1em 0;
        border-collapse:    collapse;
        border-spacing:     0;
        page-break-inside:  avoid;
        background:         #fff;
    }
td,
th
    {
        padding:            .2em .3em;
        border:             1px solid #bbb;
        vertical-align:     top;
        font-size:          1em;
    }
th,
caption
    {
        font-weight:        bold;
    }
tbody tr:nth-child(even)
    {
        background:         #f4f4f4;
    }
tr:nth-child(1n+0) > *
    {
        border-width:       0 1px;
    }

/*  Liste aller Artikel */
.sortable th
    {
        cursor:             pointer;
    }
.sortable th.sorttable_nosort
    {
        cursor:             text;
    }
#allposts
    {
        margin-left:        0;
    }
#allposts td:first-child
    {
        width:              100%;
    }
#allposts a
    {
        text-decoration:    none;
    }
#allposts a:hover
    {
        text-decoration:    underline;
    }
#allposts tr:nth-child(1n+0)
    {
        border:             0;
    }
#allposts tr:nth-child(1n+0) td,
#allposts tr:nth-child(1n+0) th
    {
        border-width:       0;
        padding:            .2em .4em;
    }
#allposts tbody tr:hover
    {
        outline:            1px solid #999;
    }
#allposts th:last-child
    {
        min-width:          3em;
    }
#allposts td:last-child
    {
        text-align:         right;
    }
#allposts td:first-child a
    {
        display:            block;
    }
#allposts td:last-child a
    {
        display:            block;
    }

Nicht sehr effizient, ich weiß. Nach dem nächsten Redesign wird das sicher besser aussehen.

23 Kommentare

  1. Frank am 06.01.2010 · 15:22

    Ich nutze eine kleine Übrgabe an den Loop, mache aber auch keine Tabelle darus und dann ist es recht schlank, auch für NichtPHPler zu lesen, denke ich.

    
    <ul>
    <?php
    query_posts("posts_per_page=-1");
    if (have_posts()) : while (have_posts()) : the_post(); ?>
    	<li><small>#<?php the_ID(); ?>, <?php the_time('m/y') ?> </small> <a href="<?php the_permalink() ?>" rel="bookmark" title="Permanent Link zu <?php echo htmlentities( get_the_title() ); ?>"><?php the_title(); ?></a> <small>(<?php comments_number('0','1','%');?>)</small></li>
    <?php endwhile; ?>
    </ul>
    
  2. [asterix] am 06.01.2010 · 16:24

    Sehr praktisch vielen Dank. Ich denke, ich werde das bei gelegenheit auch auf meinem Blog einbauen.

  3. Struppi am 06.01.2010 · 18:44

    In dem zusammenhang hatte ich, soweit ich mich erinnere, schon einmal meine Version von sorttable angepriesen. Damit sparst du den customkey, da es auch mit dem deutschen Zeitformat zurecht kommt. Und es ist darüber hinaus, um einiges schneller. http://javascript.jstruebig.de/javascript/74/

  4. Thomas Scholz am 06.01.2010 · 19:24

    @Struppi: Danke, das sehe ich mir am Wochenende mal genau an.
    Ich habe eigentlich vor, beim nächsten Redesign all meine lose zusammengestückelten Scripte zugunsten jQuerys aufzugeben; deshalb habe ich mich um Ersatz bisher nicht weiter gekümmert, obwohl mir die Grenzen meiner aktuell verwendeten Skripte durchaus bewußt sind.

    Bei deinem Skript irritiert mich die separate ltrim.js: Sie prüft nicht, ob der Browser das schon nativ kann; und warum das zwei getrennte Dateien sind oder sein müssen, verstehe ich auch nicht so recht. Naja, das kriege ich auch selber noch raus. ☺

  5. [asterix] am 06.01.2010 · 20:13

    jQuery lädt beim Benutzer mit seinen 50 Kilobytes (komprimierte Version) aber auch nicht gerade schnell. Das war für mich bisher der einzige Grund, es nicht zu verwenden.

    Bedeutend interessanter finde ich dagegen schon «midori JS», da dieses unkomprimiert nur zwanzig Kilobytes auf die Waage bringt. Ich habe mir dieses Framework jedoch noch nicht genauer angeschaut und nehme an, es kann aufgrund seiner leichtheit nicht mit denselben Funktionen auftrumpfen wie jQuery.

    Schade.

  6. Thomas Scholz am 06.01.2010 · 20:47

    @[asterix]: Ich werde jQuery ohnehin aus dem Google-CDN einbinden. Dave Ward hat dazu mal einen guten Artikel geschrieben: 3 reasons why you should let Google host jQuery for you.
    Gerade beim Publikum dieses Blogs habe ich gute Chancen, daß die Datei schon im Cache des Lesers liegt.

    Ansonsten ist es bei jQuery wie bei WordPress: Sicher hat es auch Nachteile, aber ich habe die größte Auswahl an Plugins und Informationen, was es mir wiederum erleichtert, das bestmögliche Ergebnis für meine Leser hinzustellen.

  7. Struppi am 08.01.2010 · 10:06

    Du hast recht, als ich das Skript geschrieben hatte wußte ich noch nicht, dass manche Browser die trim Funktionen in ihren Wortschatz aufnehmen wollen. Aber das sind sowieso nur ein paar Zeilen, die natürlich auch in sort_table eingebaut werden könnte. Es müssen also nicht zwei getrennte Dateien sein, es dient einfach nur der wiederverwendbarkeit.

  8. David am 22.03.2010 · 14:36

    Wenn ich das so nutze, wirft the_permalink() mir immer den Link zur Aktuellen Seite zurück und nicht den, der innerhalb des neuen Loops zu sehen sein sollte. Dito für the_title().
    Nur echo get_permalink($post->ID) liefert das gewünschte Ergebnis. Allerdings sieht diese Methode so aus, als würde da jedes mal noch einmal eine DB-Anfrage losgelassen. Warum steht der Permalink eigentlich nicht in $post->permalink?

  9. Thomas Scholz am 22.03.2010 · 14:54

    @David: the_permalink() ist nur ein Container für get_permalink():

    function the_permalink() {
          echo apply_filters('the_permalink', get_permalink());
    }

    Ich würde hier zunächst vermuten, daß du irgendeinen Filter auf 'the_permalink' sitzen hast, der die Ausgabe verändert. Ein Plugin oder ein unausgereifter Hack in der functions.php vielleicht.

    Warum steht der Permalink eigentlich nicht in $post->permalink?

    Weil man Informationen zur Adresse nicht immer braucht, wenn man mit dem Post-Objekt arbeitet – das auch eine Seite oder ab Version 3.0 ein Menupunkt sein kann. Die »Umrechnung« geschieht also nur dann, wenn der Bedarf klar feststeht.

  10. David am 22.03.2010 · 19:32

    Weil man Informationen zur Adresse nicht immer braucht,

    Der Shortlink steht doch auch drin?

    Egal, get_permalink() funktioniert auch nur dann, wenn ich manuel die ID mitgebe. Filter sind definitiv keine drauf.

    Wenn ich es herausgefunden habe, sag ich bescheid.

  11. Thomas Scholz am 23.03.2010 · 00:04

    @David: Der Shortlink steht nicht drin – nur die unvermeidliche Post-ID, aus der man die Short-URI bilden kann.

    Falls du es brauchst oder einer der anderen Leser:

    print_r $GLOBALS['wp_filter']

    … liefert alle Filter. Eine erschreckend lange Liste, aus der man aber doch einiges lernen kann.

  12. David am 01.04.2010 · 19:44

    @David: Der Shortlink steht nicht drin – nur die unvermeidliche Post-ID, aus der man die Short-URI bilden kann.

    Was ist dann $post->guid? Dort steht bei mir genau der Shortlink drin.

  13. Thomas Scholz am 02.04.2010 · 10:30

    @David: Du hast recht; das hatte ich komplett übersehen.

  14. David am 02.04.2010 · 14:04

    Und auch wieder nicht. Denn dort steht der Shortlink (so ein unsinniges Wort) drin, wie er zum Zeitpunkt der Veröffentlichung geheißen hat. Nach einem Umzug auf eine andere Domain ist das Feld nicht mehr zu gebrauchen. Ich frage mich, wozu das überhaupt da ist. Ein Permalinkfeld, dass die Request-URI speichert würde ich für sinnvoller halten.

    Egal, angenehmes Oster-Wochenende allerseits.

  15. dueddel am 07.09.2010 · 08:23

    Super, danke!

    Für WordPress-Unerfahrene wie mich, die vorher nicht wussten, wie man überhaupt eigene Templates baut, ein schneller und unkomplizierter Weg ans Ziel.
    Ich habe zwar keine Artikelliste, sondern eine Übersicht für Kategorien gemacht, aber der Denkanstoß war der richtige.

    Viele Grüße nach Halle.
    Arvid

  16. Steffen am 11.10.2010 · 20:42

    @[asterix]:

    jQuery lädt beim Benutzer mit seinen 50 Kilobytes (komprimierte Version) aber auch nicht gerade schnell. Das war für mich bisher der einzige Grund, es nicht zu verwenden.

    Die komprimierte Version von jQuery hat gerade mal 24kb (gzip). Unabhängig davon wären 50Kb nun nicht unbedingt ein k.o kriterium. Jedenfalls nicht wenn man das Framework effektiv nutzt. Für profane Aktionen wie ein/ausblenden würde ich es nicht einsetzen aber sobald es umfangreichere Dinge sind kann man da sehr gut mit arbeiten. Vor allem spart es mir Zeit in der Entwicklung.

  17. Steffen am 11.10.2010 · 20:48

    @Steffen: «midori JS hat uncompressed übrigens auch 51K ;)

  18. andre.roesti am 11.10.2010 · 21:18

    @Steffen: Stimmt, ich habe mich mit den 21 KB verlesen. ☺ Da jQuery das beliebteste JS-Framework ist, wäre es bestimmt auch meine erste Wahl, wenn ich je ein Framework brauche.

    Trotzdem kann mich die jQuery-Dateigrösse nicht überzeugen - ich finde es werden für viele Websites viele Funktionen mitgeschleppt, die schlussendlich nie eingesetzt werden. Gibt es für jQuery keine Möglichkeit, eine angepasste Version zu herunterladen, wie bei MooTools?

  19. Steffen am 12.10.2010 · 15:04

    @andre.roesti:

    So etwas ähliches gibt es für jQuery UI (http://jqueryui.com/download). Da kann man sich was zurecht konfigurieren. Der Core allerdinsg lässt sich nicht aufsplitten. Ich stimme dir aber zu wenn du sagst das jQuery für machne Funktion etwas oversized ist. Muss man halt abwägen ob man den Overhead in kauf nimmt oder nicht.

    Wenn ich mir aber anschaue wieviel Zeit ich sparen kann wenn ich mich um gewisse Dinge, die das Framework automatisch liefert, nicht kümmern muss nehme ich den Overhead gerne in kauf. Und mit caching und gzip ist das imho völlig ok.

  20. Peter am 25.02.2011 · 09:10

    Hallo, bin gerade auf diese Seite gestoßen - genau das, was ich suche...
    Allerdings funktioniert das bei mir nicht. Ist das Skript WP3.1 kompatibel?

    hier meine Seite: http://www.blogbildung.net/artikeluebersicht/

    sorttable.js ist richtig eingebunden. Laut Opera-Dragonfly Abbruch mit der Fehlermeldung "Uncaught exception: TypeError: Cannot convert 'node' to object"

    Wäre toll, wenn ich das Skript zum Laufen bekommen könnte

  21. Thomas Scholz am 25.02.2011 · 11:41

    @Peter: Passe die Zeile an, über der steht: // ANPASSEN!.

  22. Peter am 25.02.2011 · 13:08

    @Thomas
    Vielen Dank für die schnelle Hilfe, ich habe jetzt den Aufruf von end_on_word() ganz entfernt und es klappt. Sonst weiß ich aufgrund meiner Vorkenntnisse nicht, was ich in der Zeile anpassen kann.

    Aber ein Problem habe ich trotzdem noch: Die Tabelle lässt sich nur in einer Richtung sortieren (immer absteigend) beim nochmaligen Anklicken der Tabellen-Zelle passiert nichts.

    Ich hoffe mal, das hängt nicht mit meiner Verschmähung der end_on_word-Funktion zusammen ;-)

  23. Thomas Scholz am 25.02.2011 · 13:54

    @Peter: Du mußt irgendwo in deinen PHP-Dateien die Funktion end_on_word() definieren. Den Code dafür findest du unter dem Link im selben Kommentar.
    Mit der Sortierung hat das freilich nichts zu tun, da kann dir der Javascript-Debugger mehr sagen.