Search through custom post type and custom fields takes 5 minutes

I got strange problem and I’m stuck. I have custom post type with around 15 custom fields.

I moved data from old db (not WP) by using wp_insert_post ,update_post_meta and wp_set_object_terms.

Read More

All went good. All vcards works fine. I got 3500 vcards and now when I try to search some vcards – search just freeze for 10 minutes then i get timeout. Same thing is in admin panel if I try to search in custom post type menu search takes 10 minutes and dies…
So I have a question is wordpress capable to handle that amount of custom post type posts ? or i made some mistake in coding ? If You need any kind of code to show please tell me i will paste it here since now i dont even know where to start search.

Best Regards
Charles


Here is a code:

First of all i drop other pages from search – i need only my custom post type

function search_types($query) {
if ( $query->is_search ) 
{
    $query->set('post_type', 'vcard');

}
return $query;

This part of code i found on net and just adjusted it to my needs:
I grab all custom fields ( now in code i got only 1 field becouse of testing – normally is about 15)

function custom_fields_search() {
global $wpdb;

$sql = "SELECT meta_key FROM ". $wpdb->prefix . "postmeta mk WHERE mk.meta_key LIKE 'companyKeyWords'";
$results = $wpdb->get_results( $sql );

if ( $results ) :
    foreach ($results as $result) {
        $custom_fields[] = $result->meta_key;
    }
endif;

return $custom_fields;

Now those 3 function with filter

function custom_search_groupby($groupby) {
global $wpdb, $wp_query;

$groupby = "$wpdb->posts.ID";

return $groupby;
function custom_search_join($join) {
global $wpdb, $wp_query;

if ( is_search() && isset($_GET['s']) ) {

    $join  = " INNER JOIN $wpdb->term_relationships AS r ON ($wpdb->posts.ID = r.object_id) ";
    $join .= " INNER JOIN $wpdb->term_taxonomy AS x ON (r.term_taxonomy_id = x.term_taxonomy_id) ";
    $join .= " AND x.taxonomy = '".GO_TAX_CAT."'";


    // if an ad category is selected, limit results to that cat only
    $catid = $wp_query->query_vars['cat'];

    if ( !empty($catid) ) :

        // put the catid into an array
        (array) $include_cats[] = $catid;

        // get all sub cats of catid and put them into the array
        $descendants = get_term_children( (int) $catid, GO_TAX_CAT );

        foreach ( $descendants as $key => $value )
            $include_cats[] = $value;

        // take catids out of the array and separate with commas
        $include_cats = "'" . implode( "', '", $include_cats ) . "'";

        // add the category filter to show anything within this cat or it's children
        $join .= " AND x.term_id IN ($include_cats) ";

    endif; // end category filter


    $join .= " INNER JOIN $wpdb->postmeta AS m ON ($wpdb->posts.ID = m.post_id) ";
    $join .= " INNER JOIN $wpdb->terms AS t ON x.term_id = t.term_id ";

}

return $join;
}

function custom_search_where($where) {
global $wpdb, $wp_query;
$old_where = $where; // intercept the old where statement
if ( is_search() && isset($_GET['s']) ) {

    // get the custom fields to add to search
    $custom_fields = custom_fields_search();
    $customs = $custom_fields;

    $query = '';

    $var_q = stripslashes($_GET['s']);
    //empty the s parameter if set to default search text
    if ( __('What are you looking for?','go') == $var_q ) {
        $var_q = '';
    }

    if ( isset($_GET['sentence']) || $var_q == '' ) {
        $search_terms = array($var_q);
    }
    else {
        preg_match_all('/".*?("|$)|((?<=[\s",+])|^)[^\s",+]+/', $var_q, $matches);
        $search_terms = array_map(create_function('$a', 'return trim($a, ""'\n\r ");'), $matches[0]);
    }

    if (!isset($_GET['exact']) ) $_GET['exact'] = '';

    $n = ( $_GET['exact'] ) ? '' : '%';

    $searchand = '';

    foreach ( (array)$search_terms as $term ) {
        $term = addslashes_gpc($term);

        $query .= "{$searchand}(";
        $query .= "($wpdb->posts.post_title LIKE '{$n}{$term}{$n}')";
        $query .= " OR ($wpdb->posts.post_content LIKE '{$n}{$term}{$n}')";
        $query .= " OR ((t.name LIKE '{$n}{$term}{$n}')) OR ((t.slug LIKE '{$n}{$term}{$n}'))";

        foreach ( $customs as $custom ) {
            $query .= " OR (";
            $query .= "(m.meta_key = '$custom')";
            $query .= " AND (m.meta_value  LIKE '{$n}{$term}{$n}')";
            $query .= ")";
        }

        $query .= ")";
        $searchand = ' AND ';
    }

    $term = $wpdb->escape($var_q);

    if ( !isset($_GET['sentence']) && count($search_terms) > 1 && $search_terms[0] != $var_q ) {
        $query .= " OR ($wpdb->posts.post_title LIKE '{$n}{$term}{$n}')";
        $query .= " OR ($wpdb->posts.post_content LIKE '{$n}{$term}{$n}')";
    }

    if ( !empty($query) ) {

        $where = " AND ({$query}) AND ($wpdb->posts.post_status = 'publish') ";

        // setup the array for post types
        $post_type_array = array();

        // always include the ads post type
        $post_type_array[] = GO_POST_TYPE;


        // build the post type filter sql from the array values
        $post_type_filter = "'" . implode("','",$post_type_array). "'";

        // return the post type sql to complete the where clause
        $where .= " AND ($wpdb->posts.post_type IN ($post_type_filter)) ";

    }
}

return( $where );

At the end, I applyfilters :

add_filter('posts_join', 'custom_search_join');
add_filter('posts_where', 'custom_search_where');
add_filter('posts_groupby', 'custom_search_groupby');

Related posts

Leave a Reply

1 comment

  1. You got a preg_match_all(), various JOINs, anonymous/lambda functions. In short: Everything that makes debugging hard and is performance wise a no-go.

    In short: You should use a meta_query instead. Take a look at