WordPress search: pretty URLs (permalinks), custom post types and pagination

I have three separate search boxes on my website: species CPT search, glossary CPT search and a general search which I’d like to search post and species post types.

My questions are threefold,

Read More
  1. What’s the most efficient/effective code to make pretty search URLs, and is there a reason that WordPress doesn’t activate these by default?
  2. Bearing #1 in mind, what code do I need to use in searchform-species, searchform-glossary, search and searchresults to specify that my species search will only return species results, glossary will return glossary results, etc.
  3. How do I incorporate pagination?

The code I’m currently attempting is as follows:

CODE FOR #1

add_action( 'template_redirect', 'my_rewrite' );
function my_rewrite() {

    if ( is_search() and false === strpos( $_SERVER['REQUEST_URI'], '/search/' ) ) {
        wp_redirect( get_bloginfo( 'home' ) . '/search/' . str_replace( ' ', '+', str_replace( '%20', '+', get_query_var( 's' ) ) ) );
        exit();
    }

}

CODE FOR #2 & #3

searchform.php

<?php
    $search_query = get_search_query();
    if (!$search_query) {
        $search_query = "SEARCH";
    }
?>
<form id="topbar_search" action="<?php echo home_url( '/' ); ?>" method="post">
    <p>SEARCH</p>
    <input type="text" size="50" value="<?php echo $search_query; ?>" name="s" id="s" class="topbar_longinput default-value" />
    <input type="submit" value="GO" class="topbar_submit" />
    <p class="tinylinks"><a href="#1">advanced search</a></p>
</form>

searchform-species.php

<h1 class="profilesearch">PROFILE<span class="white">SEARCH</span></h1>
<form id="profilesearch" action="<?php echo home_url( '/' ); ?>" method="post">
    <input type="hidden" name="type" value="profile" />

    <input type="text" size="50" class="default-value" value="SEARCH" name="s" />
    <input type="submit" value="GO" class="profilesearch_submit" />
    <!-- <p class="tinysearch"><a href="/dev/advanced-search/">ADVANCED SEARCH</a></p> -->
    <input type="checkbox" name="showthumbnails" id="showthumbnails" class="checkbox" <?php if ($_POST["showthumbnails"] == "on") { echo 'checked="checked" '; } ?>/><label for="showthumbnails">HIDE THUMBNAILS</label>
</form>

search.php

    if (isset($_REQUEST["type"])) {
        switch ($_REQUEST["type"]) {
            case "profile" :
                $post_type = "species";
                break;
            case "glossary" :
                $post_type = "glossary";
                break;
            default :
                $post_type = array( 'post', 'species' );
                break;
        }
    } else {
        $post_type = array( 'post', 'species' );
    }

    $paged = (get_query_var('paged')) ? get_query_var('paged') : 1;

    $args = array(
        's' => $search_term,
        'post_type' => $post_type,
        'paged' => $paged
    );
?>

<?php get_template_part('searchresults'); ?>

What’s currently happening is this:

The individual searches work, but the pagination doesn’t. When I click my next/previous_posts_link button, it adds /page/2/ to the URL and does nothing. If I try to echo out the get_query_var('page') it returns NULL. If I try to echo out 'paged' instead, it returns 0.

Additionally when a user clicks this link, the $search_query variable from searchform.php is displaying as page/bettas (where bettas is the original query).


Ideally what I’d like to happen is this:

  1. In the “general search”, a user enters betta. The URL changes to /search/betta which lists any post or species content containing the word betta.
  2. In the “species search”, a user enters betta. The URL changes to /search/betta/species (or whatever is best for SEO) and displays a list of only species content containing the word betta.
  3. The same user as #2 then clicks the Next button (previous_posts_link). The URL changes to /search/betta/species/page/2 and the user gets to see the next 25 species listed.

I’m a complete novice at WP rewriting and pagination so any assistance would be greatly appreciated.

Related posts

Leave a Reply

1 comment

  1. Pagination can be done in exactly the same way it works everywhere else in the search archive template.

    There’s no need for your custom query and type variable in search.php either. To search for a particular custom post, you can either modify the query, or you can go to that posts archive and append the search query, e.g.

    example.com/event_post_type/?s=term

    The same is true of any category or taxonomy archive, simply adding ?s=searchterm on the end will turn it into a search query, just like adding /feed/ to the end of URL will give you an RSS2 feed for that particular page/archive content.

    You’re task in prettifying this would involve adding an extra rewrite rule to convert that into something nicer, e.g.:

    function search_rewrite( $wp_rewrite ) {
    
        $feed_rules = array(
            'search/(.+)/events'    =>  'index.php?post_type=events&s='. $wp_rewrite->preg_index(1)
        );
    
        $wp_rewrite->rules = $feed_rules + $wp_rewrite->rules;
    }
    // refresh/flush permalinks in the dashboard if this is changed in any way
    add_filter( 'generate_rewrite_rules', 'search_rewrite' );
    

    Would allow you to do example.com/search/searchterm/events, although i advise /events/search/searchterm as a better way of doing it.

    Use the monkeyman rewrite rules analyser plugin to test your changes, and you can find more details about rewrite rules in this answer here: Pretty URL with add_query_var