0

I have made lot of research and have tested lot of recommended codes, but still can't find the right way to make it work. Pagination links not working. It is navigating me to the 404 page (nothing found on /?s=ddd page). In Some cases it is working, but can't understand why not for all cases ( WORKS ) here is the code I am using. The strange thing is , this code working great on other website ( LINK ), but not working in the current on ( link ) . Permalinks was setted to ' /%category%/%postname%/ ', but I have tested with other types. Still no result.

global $wpdb;
global $wp_query;
// If you use a custom search form
// $keyword = sanitize_text_field( $_POST['keyword'] );
// If you use default WordPress search form
$keyword = get_search_query();
$keyword_meta = '%'.like_escape( $keyword ) . '%';
$keyword_title = like_escape( $keyword ) . '%';
$post_title_ids = $wpdb->get_col( $wpdb->prepare( "SELECT {$wpdb->posts}.ID FROM {$wpdb->posts} 
        WHERE {$wpdb->posts}.post_title LIKE '%s'", $keyword_title ) );

// Search in all custom fields
$post_ids_meta = $wpdb->get_col( $wpdb->prepare( "SELECT {$wpdb->posts}.ID FROM {$wpdb->postmeta} 
    LEFT JOIN {$wpdb->posts} ON {$wpdb->posts}.ID = {$wpdb->postmeta}.post_id
        WHERE (meta_key = '_key' AND meta_value LIKE '%s') GROUP BY {$wpdb->posts}.ID", $keyword_meta ) );

$paged =(get_query_var('paged')) ? get_query_var('paged') : 1;
$post_ids = array_merge($post_title_ids,$post_ids_meta);
// Query arguments
$args = array(      
    'post_status' => 'publish',
    'paged' => $paged,
    'orderby'=>'post__in',
    'post__in' => $post_ids
);

$query = new WP_Query ( $args );
//set_include_order($query, $post_ids);

$temp = $wp_query; 
  $wp_query = null; 
  $wp_query = $query;

if ($query->have_posts() ):
    while ($query->have_posts() ) : $query->the_post(); ?>
.
.
HTML
.
.
<?php endwhile; 
endif;?>


<div class="paged_links">
            <?php                   
            $big = 999999999; // need an unlikely integer           
            echo paginate_links( array(
                'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
                'format' => '?paged=%#%',
                'posts_per_page' => 10,
                'current' => max( 1, get_query_var('paged') ),
                'total' => $query->max_num_pages,
                'mid_size'=>2,
                'next_text'=>_("&raquo;"),
                'prev_text'=>_("&laquo;"),
            ) );
            $wp_query = null; 
            $wp_query = $temp; 
             ?>
    </div>
0

1 Answer 1

1

You should use pre_get_post action to alter the search query. It is much better approach and you will avoid unnecesary queries (actually, with your code, WordPress already performed the database query for the current request but you discard it and perform a new database query).

add_action( 'pre_get_posts', 'custom_search_query' );
function custom_search_query( $query ) {
    // Alter only main query, in frontend and for search requests
    if( $query->is_search && ! is_admin() && $query->is_main_query() ) {

        $meta_query = array(
            'relation' => 'OR'
        );
        $meta_query[] = array(
            'key'     => 'some_key',
            'value'   => get_search_query(),
           ' compare' => 'LIKE',
        );
        $meta_query[] = array(
           'key'     => 'some_other_key',
           'value'   => get_search_query(),
           'compare' => 'LIKE',
        );

        // The 'OR' relation make that posts
        // are required to match at least one the meta queries.
        // If that is not what you want, we need some other logic
        // Maybe including a fake meta query that always verify to true?

        $query->set( 'meta_query', $meta_query );

    }
}

If you want to include any custom field, even the custom fields you don't know about, you need to filter the join and where clausules of the main query (source):

<?php
/**
 * Extend WordPress search to include custom fields
 *
 * http://adambalee.com
 */

/**
 * Join posts and postmeta tables
 *
 * http://codex.wordpress.org/Plugin_API/Filter_Reference/posts_join
 */
function cf_search_join( $join ) {
    global $wpdb;

    if ( is_search() ) {    
        $join .=' LEFT JOIN '.$wpdb->postmeta. ' ON '. $wpdb->posts . '.ID = ' . $wpdb->postmeta . '.post_id ';
    }

    return $join;
}
add_filter('posts_join', 'cf_search_join' );

/**
 * Modify the search query with posts_where
 *
 * http://codex.wordpress.org/Plugin_API/Filter_Reference/posts_where
 */
function cf_search_where( $where ) {
    global $pagenow, $wpdb;

    if ( is_search() ) {
        $where = preg_replace(
            "/\(\s*".$wpdb->posts.".post_title\s+LIKE\s*(\'[^\']+\')\s*\)/",
            "(".$wpdb->posts.".post_title LIKE $1) OR (".$wpdb->postmeta.".meta_value LIKE $1)", $where );
    }

    return $where;
}
add_filter( 'posts_where', 'cf_search_where' );

/**
 * Prevent duplicates
 *
 * http://codex.wordpress.org/Plugin_API/Filter_Reference/posts_distinct
 */
function cf_search_distinct( $where ) {
    global $wpdb;

    if ( is_search() ) {
        return "DISTINCT";
    }

    return $where;
}
add_filter( 'posts_distinct', 'cf_search_distinct' );
?>

Now you can use standard template hierarchy, you don't need custom pagination stuff and avoid unnecessary database queries.

6
  • I have tried your code, but Now I don't get any result. Feb 5, 2016 at 9:23
  • Which one of the two methods have you tried? Second method should work as it is; in the frist method you need to change the values of the custom fields keys to the correct values. I can not know exactly the code you need for the first method, but this is defintely the correct approach, in my opinion. Also, note, that if you use this method your search archive template must include the standar loop from main query.
    – cybmeta
    Feb 5, 2016 at 9:28
  • If you have tried the first method, the OR relation between the meta queries makes that posts need to match at least one. But that logic can be changed to fit your needs.
    – cybmeta
    Feb 5, 2016 at 9:36
  • I am trying the second one, but I guess it works not properly . For example dev1.euriconsult.net/?s=IVOIRE there should be more then 50 posts, but it returns only two. Feb 5, 2016 at 10:07
  • I can see exactly 51 results on that page.
    – cybmeta
    Feb 5, 2016 at 10:40

Your Answer

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

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