WordPress: Suchergebnisse nach Inhaltstypen filtern

Die Suchergebnisse in WordPress können besonders bei der Verwendung von verschiedenen Inhaltstypen schnell unübersichtlich werden. Mit Hilfe einer Filter-Funktion nach verschieden Inhaltstypen lässt sich diese Unübersichtlichkeit verhindern und bietet zusätzlich die Möglichkeit einer Priorisierung. Produkte oder Leistungen können beispielsweise höher priorisiert werden als Blog-Beiträge oder Seiten.

Verschiedene Inhaltstypen in WordPress

In WordPress gibt es verschiedene Inhaltstypen (Post Types). In einer Standard-Installation sind das unter anderem Seiten (page) und Beiträge (post). Plugins wie beispielsweise die Shop-Erweiterung »WooCommerce« bringen weitere Inhaltstypen wie Produkte, etc. mit, die die Standard-Inhaltstypen erweitern.

Zusätzlich kann das System um eigene Inhaltstypen erweitert werden. Hier spricht man von »Custom Post Types«. Ein nützliches Tool zum Erstellen von »Custom Post Types« findet ihr hier.

Beispiel (nach Styling) einer Suchergebnis-Seite mit Unterteilung nach Inhaltstypen

Inhaltstypen aus Suche ausschließen

Es kommt vor, dass man nicht immer alle Inhaltstypen auch in der Suche integriert haben will.
Wenn man ein »Custom Post Type« aus der Suche ausschließen will, reicht es in den »Attributen« den Wert exclude_from_search auf true zu setzen.

Schwieriger wird es, bei den Standard-Inhaltstypen oder bei Inhaltstypen die von Plugins erstellt wurden, da man hier nicht ohne weiteres an den Code ran kommt. Hierfür könnt ihr das folgende Code-Snippet in eure functions.php schreiben und den Slug des auszuschließenden Inhaltstypen verändern.

function kb_exclude_from_search($post_type){
  global $wp_post_types;

  $wp_post_types['page']->exclude_from_search = true;
  add_post_type_support( 'page', 'page-attributes' );
}
add_action('registered_post_type', 'kb_exclude_from_search', 10, 2 );

Inhaltstypen in der Suche priorisieren

Um die einzelnen Inhaltstypen in der Suche zu priorisieren, schreibt folgenden Code in eure functions.php und tragt alle eure Inhaltstypen vom Wichtigsten zum am wenig Wichtigsten nach dem Beispiel ein.

WICHTIG: Alle Inhaltstypen die nicht von der Suche ausgeschlossen sind müssen hier berücksichtigt werden, da die Suche sonst Fehler erzeugt!

function kb_order_post_types($a, $b) {
  $order = [ 'product' => 0, 'post' => 1, 'page' => 2 ];
  return $order[$a] - $order[$b];
}

Filter-Navigation erstellen und integrieren

Die Ausgabe der Suche wird in WordPress über die search.php gesteuert. Den folgenden Code müsst ihr nun in diese Datei zwischen dem Header (get_header()) und dem Footer (get_footer()) integrieren.

Kurz zusammengefasst, sagen wir dem System damit folgendes:

  1. Hole alle »Post Types« die nicht aus der Suche ausgeschlossen wurden
  2. Erstelle den globalen Search-Query für alle Suchergebnisse
  3. Prüfe ob der Parameter search_type gesetzt ist und vergebe die »Post Types« danach
  4. Gehe die Suchergebnisse durch und zähle die Anzahl der einzelnen Inhalte in den »Post Types«
  5. Ordne die Post Types (mit unserer zuvor in der functions.php integrierten Priorisierung)
  6. Gib einen Hinweistext aus, wieviele Ergebnisse insgesamt gefunden wurden
  7. Baue die Filter-Navigation (inkl. Anzahl der Ergebnisse pro Inhaltstyp)
// Hole alle »Post Types« die nicht aus der Suche ausgeschlossen wurden
$posttypes = get_post_types(array('exclude_from_search' => false));

// Erstelle den globalen Search-Query für alle Suchergebnisse
$global_search_args = array(
  'post_type' => $posttypes,
  'posts_per_page' => -1,
  's' => get_search_query(),
  'orderby' => 'relevance',
);
$global_search_query = new WP_Query($global_search_args);

// Prüfe ob der Parameter »search_type« gesetzt ist und vergebe die »Post Types« danach
if(isset($_GET['search_type'])) {
  $posttype = $_GET['search_type'];
} else {
  $posttype = $posttypes;
}

// Gehe die Suchergebnisse durch und zähle die Anzahl der einzelnen Inhalte in den »Post Types« 
$posttype_arr = array();
$post_arr = array();
foreach($global_search_query->posts as $post) {
  $posttype_arr[] = $post->post_type;
  $post_arr[] = $post->ID;
}
$posttypes_in_search = array_count_values($posttype_arr);

// Ordne die Post Types
uksort($posttypes_in_search, 'kb_order_post_types');

// Gib einen Hinweistext aus, wieviele Ergebnisse insgesamt gefunden wurden
echo '<p>'.sprintf(_nx('Your search for „%1$s“ returned %2$s result.','Your search for „%1$s“ returned %2$s results.', $global_search_query->found_posts, 'Search result count','kb-theme'),get_search_query(),number_format_i18n( $global_search_query->found_posts )). '</p>';

// Baue die Filter-Navigation
if($posttypes_in_search) { ?>
  <ul>
  <?php foreach($posttypes_in_search as $posttype => $count) { ?>
    <li class="<?php if(isset($_GET['search_type']) && $_GET['search_type'] == $posttype) { echo ' current'; } ?>">
      <a href="<?php echo esc_url( home_url()).'?s='.urlencode(get_search_query()).'&search_type='.$posttype; ?>">
        <?php echo get_post_type_object($posttype)->label; ?>
        <span>(<?php echo $count; ?>)</span>
      </a>
    </li>
  <?php } ?>
</ul>
<?php }

Gefilterte Suchergebnisse ausgeben

Zwischen dem Code der Filter-Navigation und dem Footer (get_footer()) in der search.php muss nun der Code für die Ausgabe der Suchergebnisse integriert werden.
Die Suchergebnisse erhalten wir durch Hilfe eines WP_Query dem wir Argumente übergeben. Einige dieser Argumente übernehmen wir aus dem Code für die Filter-Navigation. Als Ausgabe benutzen wir die get_template_part Funktion. Diese Funktion müsst ihr je nach eurem verwendeten Theme anpassen, um die gewünschte Ausgabe zu erhalten.

Über paginate_links haben wir eine Pagination integriert, die greift, wenn es mehr Suchergebnisse gibt, als auf einer Seite angezeigt werden sollen. Die Einstellung der Anzahl könnt ihr im Backend unter »Einstellungen → Lesen → Blogseiten zeigen maximal« finden.

// Erstelle den Search-Query
$count = get_option('posts_per_page', 12);
$paged = get_query_var('paged') ? get_query_var('paged') : 1;
$offset = ($paged - 1) * $count;
$posttypes = isset($_GET['search_type']) ? $_GET['search_type'] : $posttypes;
$search_args = array(
  'post_type' => $posttypes,
  'posts_per_page' => $count,
  'post__in' => $post_arr,
  'orderby' => 'post__in',
  'paged' => $paged,
  'offset' => $offset,
);
$search_query = new WP_Query( $search_args );

// Ausgabe der Suchergebnisse inkl. Pagination
if($search_query->have_posts() && !empty($post_arr)) {
  echo '<ul>';
  while ( $search_query->have_posts() ) { $search_query->the_post();
    get_template_part('template-parts/teaser',get_post_type()); 
  }
  echo '</ul>';
  wp_reset_postdata();

  if ($search_query->max_num_pages > 1) {
    echo '<div class="pagination">';
    echo paginate_links( array(
      'format' => 'page/%#%',
      'end_size' => '0',
      'mid_size' => '1',
      'prev_text' => '«',
      'next_text' => '»',
      'current' => max( 1, get_query_var('paged') ),
      'total' => $search_query->max_num_pages,
    ));
    echo '</div>';
  }
} else { 
  get_template_part('template-parts/content','none'); 
}

Filter-Auswahl nach Priorität automatisch festlegen

Zum Schluss müsst ihr noch den folgenden Code in eure functions.php schreiben. Dieser bewirkt, dass ihr auch bei der ersten Verwendung der Suche auf den am höchsten priorisierten Inhaltstypen eurer Suche geleitet werdet.

Hierbei übergeben wir den $_GET-Parameter search_type und leiten mit Hilfe des template_redirect Hooks die Standard-Suchergebnis-Seite um.

function kb_redirect_searchresults() {
  // Hole alle »Post Types« die nicht von der Suche ausgeschlossen wurden
  $posttypes = get_post_types(array('exclude_from_search' => false));

  if (is_search() && !is_admin() && !isset($_GET['search_type'])) {

    // Erstelle den globalen Search-Query für alle Suchergebnisse
    $global_search_args = array(
      'post_type' => $posttypes,
      'posts_per_page' => -1,
      's' => get_search_query(),
      'orderby' => 'relevance',
    );
    $global_search_query = new WP_Query($global_search_args);

    // Gehe die Suchergebnisse durch und zähle die Anzahl der einzelnen Posts in den »Post Types«
    $posttype_arr = array();
    foreach ( $global_search_query->posts as $post ) {
      $posttype_arr[] = $post->post_type;
    }
    $posttypes_in_search = array_count_values($posttype_arr);

    // Ordne die Post Types
    uksort($posttypes_in_search, "kb_order_post_types");

    // Schreibe den Parameter des am höchsten prirosierten »Post Types« mit Werten in die URL
    if($posttypes_in_search) {
      reset($posttypes_in_search);
      $current = key($posttypes_in_search);
      wp_redirect( esc_url( home_url()).'?s='.urlencode(get_search_query()).'&search_type='.$current );
      exit;
    }
  }
}
add_action('template_redirect', 'kb_redirect_searchresults');

Geschrieben von Robert Menzel

Benutzerbild

Robert arbeitet als Frontend-Developer und Web-Designer bei kulturbanause. Zu seinen Aufgaben gehören die visuelle Gestaltung und die technische Umsetzung von Websites, eCommerce-Shops oder dessen Kombination. Besonders gerne übernimmt er die Entwicklung individueller und anspruchsvoller Websites mit umfangreichen ineinandergreifenden Funktionen, getreu dem Motto: »Der beste Lack bringt nichts, wenn die Maschine darunter nicht läuft.«

Feedback & Ergänzungen – 3 Kommentare

  1. Dirk
    schrieb am 27.08.2023 um 21:36 Uhr:

    Ich sage nur: RESPEKT!
    Toll ausgeführt und detailliert beschrieben – und genau das, was ich gesucht habe.
    1000 Dank!

    Antworten
  2. Michael
    schrieb am 06.05.2021 um 18:01 Uhr:

    Muss das nicht exclude_from_search statt exclude_from_page heißen?

    Antworten
    • Robert Menzel
      schrieb am 07.05.2021 um 09:35 Uhr:

      Hallo Michael,

      da hast du natürlich recht. Wir haben es im Artikel korrigiert.

      Viele Grüße
      Robert

      Antworten

Kommentar zu dieser Seite

Wir freuen uns über Anregungen, Ergänzungen oder Hinweise zu Fehlern. Wir lesen jeden Eintrag, veröffentlichen aber nur, was den Inhalt sinnvoll ergänzt.

WordPress-Projekte mit kulturbanause

Wir wissen wovon wir reden. Wir setzen WordPress seit über 10 Jahren erfolgreich ein und realisieren maßgeschneiderte Websites auf Basis dieses großartigen CMS.

WordPress-Leistungsangebot →

Schulungen von kulturbanause

Wir bieten Seminare und Workshops zu den Themen Konzept, Design und Development. Immer up-to-date, praxisnah, kurzweilig und mit dem notwendigen Blick über den Tellerrand.

Übersicht Schulungsthemen →