0

I'm trying to set up a search page that first shows a Loop with all posts with a Custom Field meta_key of 'seek_premium' where it's meta_value is 'yes', and then a second Loop where the meta_value (same meta_key) is empty. I've got it working for the most part, but the way I'm doing it seems to break the default search functionality, in that if I do a search, no matter if a post contains the search query or not, I end up seeing all posts marked as "seek_premium" in the first loop, and all posts where "seek_premium" is empty in the second. Here's my code:

<?php if ( have_posts() ) : ?>
    <h1>My Heading</h1>
    <?php
        $premium_query = new WP_Query( array( 'meta_key' => 'seek_premium', 'meta_value' => 'yes' ) );
        while ( $premium_query->have_posts() ) : $premium_query->the_post(); 
            $seekpremium = get_post_meta( $post->ID, 'seek_premium', true );
    ?>
            SHOW PREMIUM POSTS                                                                                  
        <?php endwhile; ?> 
    <?php
        $free_query = new WP_Query( 'post_per_page=50' );
        while ( $free_query->have_posts() ) : $free_query->the_post();
            $seekpremium = get_post_meta( $post->ID, 'seek_premium', true );
            if ( !empty( $seekpremium ) )
                continue;
    ?>
            SHOW FREE POSTS                                                     
        <?php endwhile; ?> 
<?php else : ?>
    <?php include ( TEMPLATEPATH . "/unknown.php" ); ?>
<?php endif; ?>

Anyone have any ideas? I'd seen something about using $is_search as a parameter, but either am not implementing it correctly or something else with my query is wrong...

4 Answers 4

1

Alright, I just whipped something up, this should do it, but it's untested.

<?php
    $premium_args = array(
        'post_status' => 'publish',
        'meta_query'  => array(
            array(
                'key'   => 'seek_premium',
                'value' => 'yes'
            )
        )
    );
    $premium_posts = new WP_Query( $premium_args );
?>
<?php foreach( $premium_posts as $p ) : ?>
    Your output here
<?php endforeach; ?>

<?php
    $free_args = array(
        'post_status' => 'publish',
        'meta_query'  => array(
            array(
                'key'     => 'seek_premium',
                'value'   => 'yes',
                'compare' => '!='
            )
        )
    );
    $free_posts = new WP_Query( $free_args );
?>

<?php foreach( $free_posts as $p ) : ?>
    Your output here
<?php endforeach; ?>

<?php if( 0 == count( $premium_posts ) && 0 == count( $free_posts ) ) : ?>
    No results
<?php endif; ?>

I also feel like that's a lot easier to read and to follow than your current code, so if you get both working, usually the best practice is to go with the one that's most readable. Naturally, with this you can implement have_posts() and such, but I just wanted to get the general idea across, namely using meta_query.

4
  • Okay that seems to have solved the trick, m0r7if3r, as far as the results being limited to the actual search query...but it's giving me duplicate results. Each results is being displayed multiple times, and it's showing them in both the premium and free loops...
    – Nathan
    Commented Jan 24, 2012 at 15:05
  • As in the meta query is not working and you are getting premium posts in the free loop, or as in your output is borked?
    – mor7ifer
    Commented Jan 24, 2012 at 21:48
  • It was showing the correct results, in that they were limited to the keywords, but say RESULT A matched the keywords, well it was showing RESULT A in the Premium section about 20 times and RESULT A in the Free section too, also 20 times. In this instance, RESULT A was not Premium.
    – Nathan
    Commented Jan 25, 2012 at 16:44
  • Did you do a print_r() on the results, or any other sort of troubleshooting?
    – mor7ifer
    Commented Jan 25, 2012 at 18:52
0

Try this once and see if it makes a difference:

<?php if (have_posts()) : ?>
<h1>My Heading</h1>
<?php $premium_query = new WP_Query(array('meta_key' => 'seek_premium', 'meta_value' => 'yes' ));
while ($premium_query->have_posts()) : $premium_query->the_post(); 
$seekpremium = get_post_meta($post->ID, 'seek_premium', true); ?>
SHOW PREMIUM POSTS                                                                                  
<?php endwhile; wp_reset_postdata(); ?> 
<?php $free_query = new WP_Query('post_per_page=50');
while ($free_query->have_posts()) : $free_query->the_post(); 
$seekpremium = get_post_meta($post->ID, 'seek_premium', true); 
if ( !empty( $seekpremium ) ) 
continue; ?>
SHOW FREE POSTS                                                     
<?php endwhile; ?> 
<?php else : ?>
<?php include (TEMPLATEPATH . "/unknown.php"); ?>
<?php endif; ?>

I added in wp_reset_postdata() in there which (to quote the Codex) does this: "After looping through a separate query, this function restores the $post global to the current post in the main query." Didn't test this though, just thought I would throw that out there.

0

This is really easy to do with only one query and one loop. Change your query to order by your meta key...

add_filter('request', 'check_requests_for_search' );
function check_requests_for_search( $request ) {
    $dummy_query = new WP_Query();
    $dummy_query->parse_query( $request );
    if ( $dummy_query->is_search() ) {
        $request['orderby'] = 'meta_value menu_order title';
        $request['meta_key'] = 'seek_premium';
        $request['order'] = 'DESC';
    }
    return $request;
}

Note that I've ordered second by menu_order and then title here, just since that seems fairly logical. Anyway, this allows you to have normal pagination, and everything should continue to work as expected.

If you want to split the sections up, you can still do that in the one loop; put an if-clause in the loop that checks for when the value of seek_premium changes.

Cheers~

5
  • I'm trying to implement this, Matthew, as this would be the ideal solution. I was actually wanting to sort by two different factors anyway. However, this doesn't seem to be sorting correctly either. Could it be because "seek_premium" either has a value (yes) or no value at all (it's toggled via a checkbox in WP post editor)?
    – Nathan
    Commented Jan 24, 2012 at 15:12
  • You might change the 'order' to 'ASC' -- I couldn't remember which way it should go. If it's not spitting them in reverse, how is it ordering them? Commented Jan 24, 2012 at 15:23
  • Maybe I'm implementing it wrong, Matthew. Could you perhaps be a little more specific on where / how to add that code in the loop?
    – Nathan
    Commented Jan 24, 2012 at 15:34
  • I just replicated your setup and I see your issue. The way WP crafts the SQL, if the value is null the post won't be included in the result... hmm, The two easiest ways around it would be to either set seek_premium to 'No' on save if the checkbox isn't checked, or to add a hidden field above the checkbox with a value of No, e.g. <input type="hidden" name="seek_premium" value="No" />. I think perhaps in this situation, running two queries is probably the better of two evils as that will be safer. Commented Jan 24, 2012 at 15:54
  • See below answer: Meta Query args.
    – kaiser
    Commented Jan 24, 2012 at 18:34
0

I've found what I needed here: http://deadlyhifi.posterous.com/separate-posts-and-pages-in-wordpress-search

Essentially, I needed to know how to maintain the basic query WP generated (so it knew to keep it as a search result vs. just executing the exact query I was calling in the search.php file).

Thanks everyone for your input!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.