WordPress Demo by FAKTOR VIER GmbH
Version 0.8 beta2
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.
Alle der folgenden Code-Snippets können im functions.php des gewünschten Themes hinterlegt werden.
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);
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:
project) nach einem Status filternplanned), in Arbeit (progress), abgebrochen (canceled), umgesetzt (done)all)project-status) auf dem jeweiligen Projekt hinterlegtZuerst 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.
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.
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.
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.
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.
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.
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);
… folgen demnächst. Wir haben noch einige hilfreiche Tipps auf Lager. Schau doch einfach in den nächsten Wochen nochmal vorbei.