admin管理员组

文章数量:1024615

I was looking for a clean way to group my search results by posttype. I currently have 3 post types: Page, Post and Glossary. After a long search this answer in this thread got me what I needed.

The only problem is that there is no check for when a post type has no search results. If a post type has 0 results, e.g. Glossary, it still shows the post type title (and the container around the post type). I want the post type li.search-results-post-type-item to be hidden in that case.

I am not looking for a css/js hacky display: none; solution. I can't imagine this can't be done with PHP.

Thanks in advance!

Current situation

Posts

  • Post search result 1
  • Post search result 2
  • etc.

Pages

  • Page search result 1
  • Page search result 2
  • etc.

Glossary

(empty)

Desired situation

Posts

  • Post search result 1
  • Post search result 2
  • etc.

Pages

  • Page search result 1
  • Page search result 2
  • etc.

My code so far:

<?php
    $search_query = new WP_Query(
    array(
        'posts_per_page'    => 10,
        's'                 => esc_attr( $_POST['keyword'] ),
        'paged'             => $paged,
        'post_status'       => 'publish'
    )
);

if( $search_query->have_posts() ) : ?>

    <div class="search-suggestions-list-header">
        <?php echo $search_query->found_posts.' results found'; ?>
    </div>

    <ul class="search-results-list">

    <?php
        $types = array( 'post', 'page', 'glossary' );

        foreach( $types as $type ) : ?>

            <li class="search-results-post-type-item post-type-<?php echo $type ?>">

                <header class="post-type-header">
                    <h5 class="post-type-title">
                        <?php
                            $post_type_obj = get_post_type_object( $type );
                            echo $post_type_obj->labels->name
                        ?>
                    </h5>
                </header>

                <ul class="search-results-list">
                    <?php
                    while( $search_query->have_posts() ): $search_query->the_post();
                        if( $type == get_post_type() ) : ?>
                            <li class="search-results-list-item">
                                <h4 class="entry-title"><?php the_title();?></h4>
                            </li>
                        <?php
                        endif;
                    endwhile;
                    wp_reset_postdata();
                    ?>
                </ul>
            </li>

        <?php endforeach; ?>

    </ul>

<?php else:
    echo '<div class="search-suggestions-no-results">
            <p>' . __('Sorry, no results found', 'text-domain') . '</p>
        </div>';
endif;

I was looking for a clean way to group my search results by posttype. I currently have 3 post types: Page, Post and Glossary. After a long search this answer in this thread got me what I needed.

The only problem is that there is no check for when a post type has no search results. If a post type has 0 results, e.g. Glossary, it still shows the post type title (and the container around the post type). I want the post type li.search-results-post-type-item to be hidden in that case.

I am not looking for a css/js hacky display: none; solution. I can't imagine this can't be done with PHP.

Thanks in advance!

Current situation

Posts

  • Post search result 1
  • Post search result 2
  • etc.

Pages

  • Page search result 1
  • Page search result 2
  • etc.

Glossary

(empty)

Desired situation

Posts

  • Post search result 1
  • Post search result 2
  • etc.

Pages

  • Page search result 1
  • Page search result 2
  • etc.

My code so far:

<?php
    $search_query = new WP_Query(
    array(
        'posts_per_page'    => 10,
        's'                 => esc_attr( $_POST['keyword'] ),
        'paged'             => $paged,
        'post_status'       => 'publish'
    )
);

if( $search_query->have_posts() ) : ?>

    <div class="search-suggestions-list-header">
        <?php echo $search_query->found_posts.' results found'; ?>
    </div>

    <ul class="search-results-list">

    <?php
        $types = array( 'post', 'page', 'glossary' );

        foreach( $types as $type ) : ?>

            <li class="search-results-post-type-item post-type-<?php echo $type ?>">

                <header class="post-type-header">
                    <h5 class="post-type-title">
                        <?php
                            $post_type_obj = get_post_type_object( $type );
                            echo $post_type_obj->labels->name
                        ?>
                    </h5>
                </header>

                <ul class="search-results-list">
                    <?php
                    while( $search_query->have_posts() ): $search_query->the_post();
                        if( $type == get_post_type() ) : ?>
                            <li class="search-results-list-item">
                                <h4 class="entry-title"><?php the_title();?></h4>
                            </li>
                        <?php
                        endif;
                    endwhile;
                    wp_reset_postdata();
                    ?>
                </ul>
            </li>

        <?php endforeach; ?>

    </ul>

<?php else:
    echo '<div class="search-suggestions-no-results">
            <p>' . __('Sorry, no results found', 'text-domain') . '</p>
        </div>';
endif;
Share Improve this question asked Jan 8, 2019 at 9:53 JustinJustin 4511 bronze badges
Add a comment  | 

3 Answers 3

Reset to default 1

To avoid types with no results you can e.g.

  • one additional time go through the loop and count the occurrences of each type, the number of returned results is not large (only 10 per page)
  • display the type title when you encounter the first post with the given type (move to inside while loop, I know, less readable code)
  • go through the loop one time and collect post titles to the table divided into types

First option

<ul class="search-results-list">
    <?php

    $types = array( 'post', 'page', 'glossary' );
    $occurrences = [];
    while( $search_query->have_posts() )
    {
        $search_query->next_post();
        $type = $search_query->post->post_type;
        if ( !isset($occurrences[$type]) )
            $occurrences[$type] = 1;
        else
            $occurrences[$type] += 1;
    }
    rewind_posts();

    foreach( $types as $type ) : 

        if ( !isset($occurrences[$type]) )
            continue;
        ?>
        <li class="search-results-post-type-item post-type-<?php echo $type ?>">
            //
            // remaining code
            //
        </li>

    <?php endforeach; ?>
</ul>

Second option

$types = array( 'post', 'page', 'glossary' );
foreach( $types as $type ) : 

    $type_header_printed = false;
    ?>
    <?php
    while( $search_query->have_posts() ): 
        $search_query->the_post();
        if( $type == get_post_type() ) :

            // -- post type header -----
            if ( !$type_header_printed ) : 

                $type_header_printed = true;
                ?>
                <li class="search-results-post-type-item post-type-<?php echo $type ?>">
                    <header class="post-type-header">
                        <h5 class="post-type-title">
                            <?php
                                $post_type_obj = get_post_type_object( $type );
                                echo $post_type_obj->labels->name
                            ?>
                        </h5>
                    </header>                    
                    <ul class="search-results-list">

            <?php // -- header end -----
            endif; ?>

            <li class="search-results-list-item">
                <h4 class="entry-title"><?php the_title();?></h4>
            </li>
        <?php

        endif;
    endwhile;
    rewind_posts();

    if ( $type_header_printed ) : ?>
            </ul>
        </li>
    <?php endif; ?>

<?php endforeach; ?>

Third option

<ul class="search-results-list">
    <?php

    $types = array( 'post', 'page', 'glossary' );
    $posts_titles = [];
    while( $search_query->have_posts() )
    {
        $search_query->the_post();
        $type = $search_query->post->post_type;
        if ( !isset($posts_titles[$type]) )
            $posts_titles[$type] = [];

        $posts_titles[$type][] = get_the_title();
    }
    rewind_posts();

    foreach( $types as $type ) : 

        if ( !isset($posts_titles[$type]) )
            continue;
        ?>
        <li class="search-results-post-type-item post-type-<?php echo $type ?>">
            <header class="post-type-header">
                <h5 class="post-type-title">
                    <?php
                        $post_type_obj = get_post_type_object( $type );
                        echo $post_type_obj->labels->name
                    ?>
                </h5>
            </header>
            <ul class="search-results-list">

            <?php foreach( $posts_titles[$type] as $title ) : ?>
                <li class="search-results-list-item">
                    <h4 class="entry-title"><?php echo htmlspecialchars($title); ?></h4>
                </li>
            <?php endforeach; ?>

            </ul>
        </li>

    <?php endforeach; ?>
</ul>

I has the same trouble.

My solution:

  1. The $post_type array must be outside the WP_Query.
  2. The WP_Query must be inside the foreach statement.

So... Your code goes like this:

<?php
    // Here, the Types
    $types = array( 'post', 'page', 'glossary' );

    foreach( $types as $type ) :

    // Search Args better in a variable (for order purposes)
    $search_args = array(
            'posts_per_page'    => 10,
            's'                 => esc_attr( $_POST['keyword'] ),
            'paged'             => $paged,
            'post_status'       => 'publish',
            'post_type'         => $type // This line was added
        );

    $search_query = new WP_Query($search_args);

    if( $search_query->have_posts() ) : ?>

    <div class="search-suggestions-list-header">
        <?php echo $search_query->found_posts.' results found'; ?>
    </div>

    <ul class="search-results-list">

        <li class="search-results-post-type-item post-type-<?php echo $type; ?>">

            <header class="post-type-header">
                <h5 class="post-type-title">
                    <?php
                        $post_type_obj = get_post_type_object($type);
                        echo $post_type_obj->labels->name;
                    ?>
                </h5>
            </header>

            <ul class="search-results-list">
                <?php
                while( $search_query->have_posts() ): $search_query->the_post();
                    if( $type == get_post_type() ) : ?>
                        <li class="search-results-list-item">
                            <h4 class="entry-title"><?php the_title();?></h4>
                        </li>
                    <?php
                    endif; // I think you'll need for style propouses
                endwhile;
                ?>
            </ul>
        </li>

    </ul>

<?php else:
    echo '<div class="search-suggestions-no-results">
            <p>' . __('Sorry, no results found', 'text-domain') . '</p>
        </div>';
endif;

wp_reset_postdata(); // Here goes the reset

endforeach; // End Foreach ?>

Hope it helps.

Try to put <?php wp_reset_postdata(); ?> just after endif and check it is working or not and let me know if the problem is still persist.

I was looking for a clean way to group my search results by posttype. I currently have 3 post types: Page, Post and Glossary. After a long search this answer in this thread got me what I needed.

The only problem is that there is no check for when a post type has no search results. If a post type has 0 results, e.g. Glossary, it still shows the post type title (and the container around the post type). I want the post type li.search-results-post-type-item to be hidden in that case.

I am not looking for a css/js hacky display: none; solution. I can't imagine this can't be done with PHP.

Thanks in advance!

Current situation

Posts

  • Post search result 1
  • Post search result 2
  • etc.

Pages

  • Page search result 1
  • Page search result 2
  • etc.

Glossary

(empty)

Desired situation

Posts

  • Post search result 1
  • Post search result 2
  • etc.

Pages

  • Page search result 1
  • Page search result 2
  • etc.

My code so far:

<?php
    $search_query = new WP_Query(
    array(
        'posts_per_page'    => 10,
        's'                 => esc_attr( $_POST['keyword'] ),
        'paged'             => $paged,
        'post_status'       => 'publish'
    )
);

if( $search_query->have_posts() ) : ?>

    <div class="search-suggestions-list-header">
        <?php echo $search_query->found_posts.' results found'; ?>
    </div>

    <ul class="search-results-list">

    <?php
        $types = array( 'post', 'page', 'glossary' );

        foreach( $types as $type ) : ?>

            <li class="search-results-post-type-item post-type-<?php echo $type ?>">

                <header class="post-type-header">
                    <h5 class="post-type-title">
                        <?php
                            $post_type_obj = get_post_type_object( $type );
                            echo $post_type_obj->labels->name
                        ?>
                    </h5>
                </header>

                <ul class="search-results-list">
                    <?php
                    while( $search_query->have_posts() ): $search_query->the_post();
                        if( $type == get_post_type() ) : ?>
                            <li class="search-results-list-item">
                                <h4 class="entry-title"><?php the_title();?></h4>
                            </li>
                        <?php
                        endif;
                    endwhile;
                    wp_reset_postdata();
                    ?>
                </ul>
            </li>

        <?php endforeach; ?>

    </ul>

<?php else:
    echo '<div class="search-suggestions-no-results">
            <p>' . __('Sorry, no results found', 'text-domain') . '</p>
        </div>';
endif;

I was looking for a clean way to group my search results by posttype. I currently have 3 post types: Page, Post and Glossary. After a long search this answer in this thread got me what I needed.

The only problem is that there is no check for when a post type has no search results. If a post type has 0 results, e.g. Glossary, it still shows the post type title (and the container around the post type). I want the post type li.search-results-post-type-item to be hidden in that case.

I am not looking for a css/js hacky display: none; solution. I can't imagine this can't be done with PHP.

Thanks in advance!

Current situation

Posts

  • Post search result 1
  • Post search result 2
  • etc.

Pages

  • Page search result 1
  • Page search result 2
  • etc.

Glossary

(empty)

Desired situation

Posts

  • Post search result 1
  • Post search result 2
  • etc.

Pages

  • Page search result 1
  • Page search result 2
  • etc.

My code so far:

<?php
    $search_query = new WP_Query(
    array(
        'posts_per_page'    => 10,
        's'                 => esc_attr( $_POST['keyword'] ),
        'paged'             => $paged,
        'post_status'       => 'publish'
    )
);

if( $search_query->have_posts() ) : ?>

    <div class="search-suggestions-list-header">
        <?php echo $search_query->found_posts.' results found'; ?>
    </div>

    <ul class="search-results-list">

    <?php
        $types = array( 'post', 'page', 'glossary' );

        foreach( $types as $type ) : ?>

            <li class="search-results-post-type-item post-type-<?php echo $type ?>">

                <header class="post-type-header">
                    <h5 class="post-type-title">
                        <?php
                            $post_type_obj = get_post_type_object( $type );
                            echo $post_type_obj->labels->name
                        ?>
                    </h5>
                </header>

                <ul class="search-results-list">
                    <?php
                    while( $search_query->have_posts() ): $search_query->the_post();
                        if( $type == get_post_type() ) : ?>
                            <li class="search-results-list-item">
                                <h4 class="entry-title"><?php the_title();?></h4>
                            </li>
                        <?php
                        endif;
                    endwhile;
                    wp_reset_postdata();
                    ?>
                </ul>
            </li>

        <?php endforeach; ?>

    </ul>

<?php else:
    echo '<div class="search-suggestions-no-results">
            <p>' . __('Sorry, no results found', 'text-domain') . '</p>
        </div>';
endif;
Share Improve this question asked Jan 8, 2019 at 9:53 JustinJustin 4511 bronze badges
Add a comment  | 

3 Answers 3

Reset to default 1

To avoid types with no results you can e.g.

  • one additional time go through the loop and count the occurrences of each type, the number of returned results is not large (only 10 per page)
  • display the type title when you encounter the first post with the given type (move to inside while loop, I know, less readable code)
  • go through the loop one time and collect post titles to the table divided into types

First option

<ul class="search-results-list">
    <?php

    $types = array( 'post', 'page', 'glossary' );
    $occurrences = [];
    while( $search_query->have_posts() )
    {
        $search_query->next_post();
        $type = $search_query->post->post_type;
        if ( !isset($occurrences[$type]) )
            $occurrences[$type] = 1;
        else
            $occurrences[$type] += 1;
    }
    rewind_posts();

    foreach( $types as $type ) : 

        if ( !isset($occurrences[$type]) )
            continue;
        ?>
        <li class="search-results-post-type-item post-type-<?php echo $type ?>">
            //
            // remaining code
            //
        </li>

    <?php endforeach; ?>
</ul>

Second option

$types = array( 'post', 'page', 'glossary' );
foreach( $types as $type ) : 

    $type_header_printed = false;
    ?>
    <?php
    while( $search_query->have_posts() ): 
        $search_query->the_post();
        if( $type == get_post_type() ) :

            // -- post type header -----
            if ( !$type_header_printed ) : 

                $type_header_printed = true;
                ?>
                <li class="search-results-post-type-item post-type-<?php echo $type ?>">
                    <header class="post-type-header">
                        <h5 class="post-type-title">
                            <?php
                                $post_type_obj = get_post_type_object( $type );
                                echo $post_type_obj->labels->name
                            ?>
                        </h5>
                    </header>                    
                    <ul class="search-results-list">

            <?php // -- header end -----
            endif; ?>

            <li class="search-results-list-item">
                <h4 class="entry-title"><?php the_title();?></h4>
            </li>
        <?php

        endif;
    endwhile;
    rewind_posts();

    if ( $type_header_printed ) : ?>
            </ul>
        </li>
    <?php endif; ?>

<?php endforeach; ?>

Third option

<ul class="search-results-list">
    <?php

    $types = array( 'post', 'page', 'glossary' );
    $posts_titles = [];
    while( $search_query->have_posts() )
    {
        $search_query->the_post();
        $type = $search_query->post->post_type;
        if ( !isset($posts_titles[$type]) )
            $posts_titles[$type] = [];

        $posts_titles[$type][] = get_the_title();
    }
    rewind_posts();

    foreach( $types as $type ) : 

        if ( !isset($posts_titles[$type]) )
            continue;
        ?>
        <li class="search-results-post-type-item post-type-<?php echo $type ?>">
            <header class="post-type-header">
                <h5 class="post-type-title">
                    <?php
                        $post_type_obj = get_post_type_object( $type );
                        echo $post_type_obj->labels->name
                    ?>
                </h5>
            </header>
            <ul class="search-results-list">

            <?php foreach( $posts_titles[$type] as $title ) : ?>
                <li class="search-results-list-item">
                    <h4 class="entry-title"><?php echo htmlspecialchars($title); ?></h4>
                </li>
            <?php endforeach; ?>

            </ul>
        </li>

    <?php endforeach; ?>
</ul>

I has the same trouble.

My solution:

  1. The $post_type array must be outside the WP_Query.
  2. The WP_Query must be inside the foreach statement.

So... Your code goes like this:

<?php
    // Here, the Types
    $types = array( 'post', 'page', 'glossary' );

    foreach( $types as $type ) :

    // Search Args better in a variable (for order purposes)
    $search_args = array(
            'posts_per_page'    => 10,
            's'                 => esc_attr( $_POST['keyword'] ),
            'paged'             => $paged,
            'post_status'       => 'publish',
            'post_type'         => $type // This line was added
        );

    $search_query = new WP_Query($search_args);

    if( $search_query->have_posts() ) : ?>

    <div class="search-suggestions-list-header">
        <?php echo $search_query->found_posts.' results found'; ?>
    </div>

    <ul class="search-results-list">

        <li class="search-results-post-type-item post-type-<?php echo $type; ?>">

            <header class="post-type-header">
                <h5 class="post-type-title">
                    <?php
                        $post_type_obj = get_post_type_object($type);
                        echo $post_type_obj->labels->name;
                    ?>
                </h5>
            </header>

            <ul class="search-results-list">
                <?php
                while( $search_query->have_posts() ): $search_query->the_post();
                    if( $type == get_post_type() ) : ?>
                        <li class="search-results-list-item">
                            <h4 class="entry-title"><?php the_title();?></h4>
                        </li>
                    <?php
                    endif; // I think you'll need for style propouses
                endwhile;
                ?>
            </ul>
        </li>

    </ul>

<?php else:
    echo '<div class="search-suggestions-no-results">
            <p>' . __('Sorry, no results found', 'text-domain') . '</p>
        </div>';
endif;

wp_reset_postdata(); // Here goes the reset

endforeach; // End Foreach ?>

Hope it helps.

Try to put <?php wp_reset_postdata(); ?> just after endif and check it is working or not and let me know if the problem is still persist.

本文标签: theme developmentGroup search results by post typebut hide post types with no results