Search code examples
phpwordpresssearchhookadvanced-custom-fields

How to merge 2 queries results into one using Wordpress hooks



I am pretty new to Wordpress and recently I found this problem which took me a lot of time to understand but I can't still figure out how to resolve it.
I am using the Wordpress basic search using the classic search.php.
I need to retrieve POSTS based on their post_title OR their custom field taxonomy, for example my case taxonomy is 'color', with ACF I added a new field called synonimes which is repeater field with inside N* text fields called synonim.
Basically I need to retrieve both posts with synonimes matching and post_title matching (basically the classic 's' => $value inside wordpress query args), using the hook pre_get_posts I only reached the point where I can filter the POSTS with a AND condition which is really wrong.
I don't know how to change this behavior and I gave up this way, I am now trying to merge the results I found with the primary Query in the hook.
I am now with this code here:

function filter_tax($query){
if (!is_admin() && $query->is_main_query() && $query->is_search()) {

    $args_new_query = array(
        'post_type' => MAIN_POST,
        'posts_per_page' => 12,
        'post_parent' => 0,
    );

    $new_query = new WP_Query($args_new_query);

    $search_keyword = sanitize_text_field(get_search_query());

    $matching_posts = array();

    if ($new_query->have_posts()) {
        $taxonomy_name = 'color';

        while ($new_query->have_posts()) : $new_query->the_post();
            $post_id = get_the_ID();

            $terms = wp_get_post_terms($post_id, $taxonomy_name);

            foreach ($terms as $term) {
                $synonim_values = get_field('synonimes', $taxonomy_name . '_' . $term->term_id);

                if (is_array($synonim_values)) {

                    foreach ($synonim_values as $syn) {
                        if (strpos($syn['synonim'], $search_keyword) !== false) {
                            $matching_posts[] = get_post($post_id);
                            break 2;
                        }
                    }
                }
            }
        endwhile;
        wp_reset_postdata();
    }

    if (!empty($matching_posts)) {
        /*$query->set('post__in', wp_list_pluck($matching_posts, 'ID'));*/
        $query->posts = array_merge([], $matching_posts);
    }
}
}

Unfortunately in my template I only can paginate basic search POSTS and my $matching_posts are lost and cannot be retrieved, It looks really simple but still it's taking me a lot of time.


Solution

  • I made an error by misunderstanding the inner functionality of POST__IN.
    Initially I thought i could inject POSTS by their ID, but this is wrong because I was filtering POSTS by their ID.
    So I came up with this:

    $args_basic = [
            'post_type' => $contentList,
            'numberposts' => -1,
            'post_parent' => 0,
            's' => $_GET['s'],
        ];
    
        $prev_search = get_posts($args_basic);
        $prev_search_ids = array_map(fn($item) => $item->ID, $prev_search);
        $query->set('post_type', $contentList);
    
        if (!empty($matching_posts)) {
            $ids_serach = array_merge($prev_search_ids, wp_list_pluck($matching_posts, 'ID'));
            $query->set('post__in', $ids_serach);
            $query->set('s', '');
        }
    

    This is the correct way to use POST__IN.
    I am leaving here my question and answer in case you are in the same boat, don't waste time merging queryposts!, it will never work.