WordPress Tipps #5 – Post-Listen Teil 3

Auch in diesem Beitrag dreht sich alles um das Optimieren und Erweitern der Post-Listen im WordPress-Backend. Dieses Mal befassen wir uns mit den Filtern, Unterseiten und wie man eigene Felder in die Suche einschliessen kann.

Inhalt

Alle der folgenden Code-Snippets können im functions.php des gewünschten Themes hinterlegt werden.

Monat-Filter entfernen

Für jede Post-Liste steht normalerweise ein Dropdown zur Verfügung, über welches man die Posts für einen gewissen Monat filtern kann. Da nicht alle Post-Types die man einsetzt zwingend einen solchen Filter benötigen, kann man den ganz einfach entfernen. Die folgende Zeile entfernt das Dropdown bei ALLEN Post-Types:

add_filter('months_dropdown_results', '__return_empty_array');

Meistens macht es jedoch Sinn, das Monat-Dropdown nur bei gewissen Post-Types auszublenden und nicht bei allen. Dafür werden ein paar Zeilen Code mehr benötigt. Das folgende Beispiel entfernt das Dropdown bei den Post-Types employee und project.

function months_dropdown_results_remove($months, $post_type) {
    if(in_array($post_type, array('employee', 'project'))) {
        $months = array();
    }

    return $months;
}
add_filter('months_dropdown_results', 'months_dropdown_results_remove', 10, 2);

Filter erstellen

Neben dem oben erwähnten Dropdown mit dem Monat-Filter, können relativ einfach auch eigene Filter erstellt werden. Dafür werden zwei Hooks benötigt. In dem folgenden Beispiel gehen wir von der folgenden Ausgangslage aus:

  • Wir wollen Projekte (Post-Type project) nach einem Status filtern
  • Der Filter wird als Dropdown neben den anderen Filtern angezeigt
  • Folgende Status existieren: geplant (planned), in Arbeit (progress), abgebrochen (canceled), umgesetzt (done)
  • Es gibt eine zusätzliche Standard-Option im Dropdown: Alle Status (all)
  • Der Status wurde als Post-Meta (project-status) auf dem jeweiligen Projekt hinterlegt

Filter-Dropdown erstellen

Zuerst muss ein Dropdown-Menü erstellt werden:

function restrict_manage_posts_projects() {
    global $post_type;

    // Den Filter nur für den Post-Type "project" anzeigen
    if($post_type != 'project') return;

    // Name des Filters, wird als GET-Variabel eingesetzt
    $filter_name = 'project_status';

    // Aktive Filter, falls bereits einer ausgewählt wurde
    $filter_selected = isset($_GET[$filter_name]) ? $_GET[$filter_name] : 'all';

    // Ein array mit Value/Labels
    $filter_options = array(
        'all' => 'Alle Status',
        'planned' => 'geplant',
        'progress' => 'in Arbeit',
        'canceled' => 'abgebrochen',
        'done' => 'umgesetzt'
    );

    // Das Dropdown-Menu wird zusammengebastelt
    echo "<select name='{$filter_name}'>";
    foreach($filter_options as $value => $label) {
        // Der aktive Filter wird selektiert
        $selected_attr = $filter_selected == $value ? ' selected="selected"' : '';
        echo "<option value='{$value}'{$selected_attr}>{$label}</option>";
    }
    echo "</select>";
}
add_action('restrict_manage_posts', 'restrict_manage_posts_projects', 99);

Die Reihenfolge der Filter kann mit der Hook-Priorität gesteuert werden. In dem Beispiel verwenden wir 99 damit das Dropdown-Menu ganz am Ende erscheint. Bei einem niedrigen Wert würde der Filter direkt nach den Standard-Filtern (Monat usw.) erscheinen.

In dem obigen Hook können natürlich auch mehrere Filter hinzugefügt werden. Es müssen auch nicht zwingend Dropdown-Menüs sein, es können z.B. auch Datum-Filter mit zwei Textfeldern erstellt werden, um nur Beiträge zwischen zwei bestimmten Zeitpunkten anzuzeigen. In diesem Beispiel konzentrieren wir uns jedoch lediglich auf einen einfachen Dropdown-Filter.

Filter in Query einbinden

Jetzt haben wir das Dropdown erstellt, jedoch wird der Filter noch nicht auf die Beiträge angewendet. Dies können wir mit einem kleinen Hook aktivieren:

function pre_get_posts_filter_project_status($query) {
    global $post_type;

    // Den Filter nur für den Post-Type "project" anwenden
    if($post_type != 'project') return;

    // Name des Filters, der selbe der im obigen Hook verwendet wurde
    $filter_name = 'project_status';

    // Den Filter anwenden wenn nicht "all" ausgewählt wurde
    if(isset($_GET[$filter_name]) && $_GET[$filter_name] != 'all') {
        // Erstellt ein leeres meta_query falls noch keins vorhanden ist
        if(!isset($query->query_vars['meta_query'])) {
            $query->query_vars['meta_query'] = array();
        }

        // Ergänzt das vorhandene meta_query um den Post-Status Filter
        $query->query_vars['meta_query'][] = array(
            'key' => 'project-status',
            'value' => $_GET[$filter_name]
        );
    }
}
add_filter('pre_get_posts', 'pre_get_posts_filter_project_status');

Das war schon alles, die Projekte können nun nach Status gefiltert werden.

Unterseite entfernen

Als Unterseite (auch View oder subsubsub genannt) bezeichnen wir die Links die zwischen Titel und Post-Listen angezeigt werden (z.B. Alle (21) | Veröffentlichte (17) | Entwürfe (4)). Die meisten dieser Links werden automatisch aus den verfügbaren Post-Status des jeweiligen Post-Types generiert.

Manchmal kann es vorkommen, dass man eine bestimmte Unterseite entfernen möchte. Dies kann mit einem kleinen Hook einfach erledigt werden. Das folgende Beispiel entfernt die Unterseite für die publizierten Beiträge (publish):

function remove_publish_view($views) {
    unset($views['publish']);

    return $views;
}
add_filter('views_edit-{$post-type}', 'remove_publish_view');

Um den Array-Key des Elementes herauszufinden, kann man in der HTML-Ausgabe die CSS-Klasse auf dem Listenelement nachschauen.

Unterseite mit Filter erstellen

Man kann auch eigene Unterseiten erstellen, welche nicht über einen Post-Status automatisch generiert werden. Wie im Beispiel mit dem Filter-Dropdown von oben, generieren wir auch für dieses Beispiel ein paar Filter für die Projekt-Status. Für jeden Status wird eine eigene Unterseite verlinkt und nur angezeigt, wenn mindestens ein Projekt mit diesem Status vorhanden ist.

Links erstellen

function add_project_status_views($views) {
    global $post_type;

    // Unterseiten nur für den Post-Type "project" anzeigen
    if($post_type != 'project') {
        return $views;
    }

    // Name des Filters für die Unterseiten, wird als GET-Variabel eingesetzt
    $filter_name = 'project_status';

    // Aktive Filter, falls bereits einer ausgewählt wurde
    $filter_active = isset($_GET[$filter_name]) ? $_GET[$filter_name] : 'all';

    // Ein array mit Value/Labels
    $filter_options = array(
        'planned' => 'Geplant',
        'progress' => 'In Arbeit',
        'canceled' => 'Abgebrochen',
        'done' => 'Umgesetzt'
    );

    foreach($filter_options as $value => $label) {
        // Der aktive Filter wird selektiert
        $active_class = $filter_active == $value ? ' class="current"' : '';

        // Zähle Projekte mit diesem Status
        $project_posts = get_posts(array(
            'nopaging' => true,
            'post_type' => 'project',
            'meta_key' => 'project-status',
            'meta_value' => $value
        ));

        $project_posts_count = count($project_posts);

        // Zeige Unterseite nicht an, wenn keine Projekte mit diesem Status existieren
        if(!$project_posts_count) {
            continue;
        }

        // Erstellt die URL für die Unterseite
        $filter_url = admin_url("edit.php?post_type=project&{$filter_name}={$value}");

        // Fügt die Unterseite zu den vorhandenen Seiten hinzu
        $views['project-' . $value] = "
            <a href='{$filter_url}'{$active_class}>
                {$label} <span class='count'>({$project_posts_count})</span>
            </a>
        ";
    }

    return $views;
}
add_filter('views_edit-{$post-type}', 'add_project_status_views');

Wenn der Zähler nicht erwünscht oder benötigt wird, kann dieser einfach entfernt werden. Dazu einfach das get_posts(), der count() und <span class='count'>({$project_posts_count})</span> entfernen. Das Entfernen dieses Zählers kann auch eine Verbesserung der Performance mit sich bringen.

Filter in Query einbinden

Da wir in dem obigen Beispiel genau die selben Filter und Bezeichnungen verwendet haben, können wir genau den selben Hook verwenden wie oben beim Filter-Dropdown. Wichtig ist, dass die Filter-Namen ($filter_name) übereinstimmen und richtig erkannt werden.

Eigene Felder in Suche einbinden

Sobald man eigene Custom-Fields einsetzt, ist es sinnvoll, dass diese auch bei der Backend-Suche einbezogen werden. Standardmässig wird bei dieser leider nur der Titel und Inhalt (Editor) durchsucht. Mit diesem Hook können beliebige Custom-Fields „suchbar“ gemacht werden:

function add_project_fields_to_search($where, $query) {
    // Den Filter nur für den Post-Type "project" anzeigen
    if(empty($query->query_vars['s']) || $query->query_vars['post_type'] != 'project') {
        return $where;
    }

    global $wpdb;

    // Die Keys der Felder die durchsucht werden sollen
    $fields_search = array(
        'project-title',
        'project-subtitle',
        'project-description'
    );

    // Erweitert das Post Query mit den Feldern
    $where = str_replace(
        "(wp_posts.post_title LIKE '%{$query->query_vars['s']}%')",
        "(wp_posts.post_title LIKE '%{$query->query_vars['s']}%') OR (
             SELECT COUNT(postmeta.post_id) FROM $wpdb->postmeta as postmeta
             WHERE $wpdb->posts.ID = postmeta.post_id
                 AND postmeta.meta_key IN ('" . implode("','", $fields_search) . "')
                 AND postmeta.meta_value LIKE '%{$query->query_vars['s']}%'
        ) > 0",
        $where
    );

    return $where;
}
add_filter('posts_where', 'add_project_fields_to_search', 10, 2);

Mehr Tipps …

… folgen demnächst. Wir haben noch einige hilfreiche Tipps auf Lager. Schau doch einfach in den nächsten Wochen nochmal vorbei.

Andere WordPress Tipps

Schlagwörter:

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.