WordPress search.php per custom post type
Zoekresultaten scheiden
Een aparte pagina voor case- en nieuwsresultaten
Voor een van onze klanten was ik opzoek naar een manier om per custom post type een aparte resultaat pagina te tonen. Waar dit erg eenvoudig is in een archive en een single (archive-custom_post_type.php / single-custom_post_type.php) moet je hier voor de zoekresultaten pagina iets meer moeite doen.
De oplossing bleek uiteindelijk redelijk eenvoudig, je moet alleen even een klein trucje uithalen. Zie hieronder.
Zoekformulier aanpassen
Stel dat je - net als ik - in een archive page van het custom post type "verslagen" een zoekformulier hebt, welke alleen de resultaten mag laten zien van die verslagen. Zet dan de volgende waarde extra in je zoekformulier.
<input name="post_type" type="hidden" value="verslagen" />
Je ziet de value "verslagen". Deze pas je uiteraard aan naar het custom post type dat jij zoekt. De name post_type gaan we later opvragen om een template te kunnen kiezen. Het volledige zoekformulier komt er vervolgens zo uit te zien.
<form id="searchform" action="<?php bloginfo('url'); ?>/" method="get">
<input id="s" maxlength="150" name="s" type="text" value="" class="txt" />
<input name="post_type" type="hidden" value="verslagen" />
<input type="submit" value="zoeken">
</form>
Let hierbij wederom op dat de value verslagen door jou aangepast moet worden naar het post_type dat je zoekt.
Toevoegen nieuwe search templates
We willen eigenlijk een search-verslagen.php kunnen aanmaken en dat WordPress deze template automatisch uitleest zodra er een zoekopdracht bekend is voor de verslagen custom post type. Dit is standaard niet mogelijk en daarom gaan we hier onderstaande snippet voor toevoegen:
add_filter('search_template_hierarchy', function($templates)
{
array_unshift($templates, 'search-verslagen.php');
return $templates;
});
Door array_unshift te gebruiken zorgen we ervoor dat de template “search-verslagen.php” nu vooraan de templates array komt. Dit template heeft nu prioriteit voor de standaard search.php. Er is alleen 1 probleem, de nieuwe template file wordt voor ieder gezochte post_type aangeroepen omdat er geen controle is op de gezochte post_type.
Hiervoor gaan we een aantal controles toevoegen:
add_filter('search_template_hierarchy', function($templates)
{
if (!empty($_GET['post_type']) && esc_html($_GET['post_type']) === 'verslagen') {
array_unshift($templates, 'search-verslagen.php');
}
return $templates;
});
Alleen wanneer de key “post_type” bekend is in de GET request, deze niet leeg is EN gelijk is aan onze custom post type voegen we onze template file vooraan de hiërarchie. Dit zorgt er voor dat voor de normale zoekopdrachten de standaard search.php wordt gebruikt.
De functionaliteit is nu alleen wel heel “vast” en voor iedere custom post type moeten we nieuwe checks toevoegen, dit willen we natuurlijk zo dynamisch mogelijk maken. Hiervoor gaan we eerst alle custom post types ophalen en vervolgens kunnen we met een loop controleren of er een custom post type wordt gezocht. Dit kan als volgt:
add_filter('search_template_hierarchy', function($templates)
{
// Deze argumenten zorgen er voor dat alleen post types die publiekelijk bereikbaar zijn gevonden worden.
// Het argument "_builtin" is voor intern gebruik en geeft aan of het een "native" post type is.
// Dit is voor custom post types daarom altijd "false" en voor "native" post types true.
$args = array(
'public' => true,
'_builtin' => false,
);
$custom_post_types = get_post_types($args);
// Als er geen custom post types zijn hoeven we niets toe te voegen aan de templates.
if (empty($custom_post_types)) {
return $templates;
}
// Loop over alle custom post types heen
foreach ($custom_post_types as $cpt_name) {
// Voeg alleen de custom template toe zodra er daadwerklijk naar de post type gezocht wordt in de huidige iteratie
if (!empty($_GET['post_type']) && esc_html($_GET['post_type']) === $cpt_name) {
// Zet de nieuwe template vooraan de array met array_unshift
array_unshift($templates, 'search-' . $cpt_name . '.php');
}
}
return $templates;
});
Je kan nu een nieuwe template aanmaken voor de custom post types waar je dit graag voor wil doen!