是否在搜索结果中包括用户配置文件?

时间:2018-03-27 作者:Paul \'Sparrow Hawk\' Biron

我需要包括用户配置文件,以及帖子和;页面,在前端搜索中。

我已经搜索了这个问题的解决方案(在WSE和web上的其他地方),但没有找到必须的帮助。根据我的要求,我找到的最接近的是Include Author profile in search resultsExtend WordPress search to include user search, 两者都没有合理的答案。

更明确的要求是:网站有帖子、页面和(当然)用户。当end-user 在上执行搜索front-end, 我需要搜索结果包含标题或post\\u内容包含搜索词的帖子和页面(对于前端搜索来说很正常)plus 与搜索词匹配的用户的配置文件(请参见下面关于用户与搜索词匹配的含义)。

重要的是我not 谈论搜索由给定用户编写的帖子!

需求背后的基本原理有助于理解why 我有这个要求,知道网站的一部分列出了所有用户配置文件和end-user 可以单击任何用户的名称以查看该用户的配置文件。在用户配置文件上,各种usermeta\'将显示。从end-user\'s 从这个角度来看,用户配置文件和他们可以在前端访问的帖子/页面之间没有区别。

假设给定用户的用户配置文件显示字符串“foo”(即显示的usermeta\'该用户的s包含“foo”)。当end-user 搜索“foo”,然后他们会期望该用户的个人资料显示在搜索结果中。

临时解决方案以下是我提出的解决方案。这个解决方案可行,但我觉得必须有一种更好/更容易/不那么脆弱的方法来实现这一点:

注册非公共自定义帖子类型(例如“my\\u user\\u profile”)user_register. 插入“my\\u user\\u profile”类型的帖子并添加postmeta (说“my\\u user\\u id”),其值是新注册用户的idthe_posts. 什么时候is_search() 是真的,那么做get_users() 搜索各种usermeta 中的搜索词end-user\'s 搜索然后做一个get_posts() 对于“my\\u user\\u profile”类型的帖子postmeta \'my\\u user\\u id“IN”在中找到的用户idget_users(); 然后返回原始搜索找到的帖子与我的get_posts().post_type_link (由调用get_permalink()). 当$post->post_type 是“my\\u user\\u profile”,返回get_author_posts_url() 在ID位于“my\\u user\\u ID”中的用户上postmeta 属于$post. 这是因为主题search.php 不必包含特定于上述步骤如何“增强”搜索结果的代码get_the_excerpt. 什么时候$post->post_type 是“my\\u user\\u profile”,然后返回特定usermeta 对于ID位于“my\\u user\\u ID”中的用户(请说出“my\\u摘录”)postmeta 属于$post. 这是因为主题search.php 不必包含关于上述步骤如何“增强”搜索结果的特定知识的代码,即临时解决方案的代码。[注:编辑步骤#3的代码,以更正我在转录(和清理)我的工作代码时引入的错误]

以下是我的临时解决方案的代码:

// step #1
add_action( \'init\', \'wpse_register_post_type\' );
function wpse_register_post_type() {
    $args = array(
        \'public\' => false,
        \'show_ui\' => false,
        \'supports\' => array(
            \'title\',
            \'author\',
        ),
    );
    register_post_type( \'my_user_profile\', $args );
}

// step #2
add_action( \'user_register\', \'wpse_add_user_profile_post\' );
function wpse_add_user_profile_post( $my_user_id ) {
    $user = get_user_by( \'ID\', $my_user_id );
    $args = array(
        \'post_type\' => \'my_user_profile\',
        // so that I can find them easier when manually looking thru the wp_posts table
        \'post_title\' => $user->display_name,
        \'post_status\' => \'publish\',
    );
    $post_id = wp_insert_post( $args );

    if ( ! is_wp_error( $post_id ) ) {
        update_post_meta( $post_id, \'my_user_id\', $my_user_id );
    }

    return;
}

// step #3
add_filter( \'the_posts\', array( $this, \'wpse_user_search\' ), 10, 2 );
function wpse_user_search( $posts, $query ) {
    if ( ! is_search() ) {
        return $posts;
    }

    $search_terms = explode( \' \', $query->get( \'s\' ) );
    $user_meta_keys = array( /* my usermeta keys */ );

    $args = array(
        \'fields\' => \'ID\',
        \'meta_query\' => array( \'relation\' => \'OR\' ),
    );
    // build the meta_query
    foreach ( $user_meta_keys as $meta_key ) {
        foreach ( $search_terms as $search_term ) {
            $args[\'meta_query\'][] = array(
                \'key\' => $meta_key,
                \'value\' => $search_term,
                \'compare\' => \'LIKE\',
            );
        }
    }
    $users = get_users( $args );

    // get the my_user_profile posts associated with $users
    $args = array(
        \'post_type\' => \'my_user_profile\',
        \'meta_query\' => array(
            array(
                \'key\' => \'my_user_id\',
                \'value\' => $users,
                \'compare\' => \'IN\',
            ),
        )
    );

    // make sure we don\'t call ourselves in the get_posts() below
    remove_filter( \'the_posts\', array( $this, \'user_search\' ) );

    $user_posts = get_posts( $args );

    add_filter( \'the_posts\', array( $this, \'user_search\' ), 10, 2 );

    $posts = array_merge( $posts, $user_posts );

    return $posts;
}

// step 4
add_filter( \'post_type_link\', array( $this, \'wpse_user_profile_permalink\' ), 10, 2 );
function wpse_user_profile_permalink( $post_link, $post ) {
    if ( \'my_user_profile\' !== $post->post_type ) {
        return $post_link;
    }

    // rely on WP_Post::__get() magic method to get the postmeta
    return get_author_posts_url( $post->my_user_id );
}

// step 5
add_filter( \'get_the_excerpt\', array( $this, \'wpse_user_profile_excerpt\' ), 10, 2 );
function wpse_user_profile_excerpt( $excerpt, $post ) {
    if ( \'my_user_profile\' !== $post->post_type ) {
        return $excerpt;
    }

    // rely on WP_Post::__get() magic method to get the postmeta
    $user = get_user_by( \'ID\', $post->my_user_id );

    // rely on WP_User::__get() magic method to get the usermeta
    return $user->my_excerpt;
}
正如我所说,上述方法可行,但我忍不住想,有一种更简单的方法,我只是没有想到。

备选(被拒绝的)解决方案

我想到的一个备选方案,但被拒绝,因为它似乎比上述解决方案更复杂/脆弱,是:

与上述第1项相同personal_options_update. 对于每个usermeta 我已经为用户存储的,添加为postmeta 连接到与给定用户关联的“my\\u user\\u profile”类型的帖子posts_joinposts_where 搜索各种postmeta 在第3步中添加的,与上述第4步相同,与上述第5步相同,是否有人有更简单/更不脆的解决方案?

1 个回复
SO网友:bueltge

我没有现成的解决方案。然而,我认为您应该增强查询,以便在其中包含用户字段。我认为下面的例子更能说明这一点。

这两个过滤器挂钩是必需的,它可以为查询获得如下结果:

SELECT SQL_CALC_FOUND_ROWS wpbeta_posts.ID
FROM wpbeta_posts JOIN wpbeta_users
WHERE 1=1 
AND (((wpbeta_posts.post_title LIKE \'%search_string%\')
OR (wpbeta_posts.post_excerpt LIKE \'%search_string%\')
OR (wpbeta_posts.post_content LIKE \'%search_string%\'))) 
AND wpbeta_posts.post_type IN (\'post\', \'page\', \'attachment\')
AND (wpbeta_posts.post_status = \'publish\'
OR wpbeta_posts.post_status = \'private\')
OR (wpbeta_users.display_name LIKE \'%search_string%\') 
ORDER BY wpbeta_posts.post_title LIKE \'%search_string%\' DESC, wpbeta_posts.post_date DESC
LIMIT 0, 10
您还可以通过插件(如调试对象或查询监视器)在测试中轻松读取此查询。sql查询只是一个示例,并确保不是使用它的结果。你必须玩它们,包括下面的钩子,以获得正确的结果。源get als只是从users表中添加一个字段的示例display_name. 也许一个sql“书呆子”可以帮上忙。

// Enhance the JOIN clause of the WP Query with table users.
add_filter( \'posts_join\', function( $join, $wp_query ) {

    // No search string, exit.
    if ( empty( $wp_query->query_vars[\'s\'] ) ) {
        return $join;
    }

    global $wpdb;
    $join .= \' JOIN \' . $wpdb->users;

    return $join;
}, 10, 2 );

// Enhance WHERE clause of the WP Query with user display name. 
add_filter( \'posts_where\', function( $where, $wp_query ) {

    // No search, exit.
    if ( ! is_search() ) {
        return $where ;
    }

    global $wpdb;
    $where .= \' OR (\' . $wpdb->users . \'.display_name LIKE \\\'%\' . esc_sql( $wp_query->query_vars[\'s\'] ) . \'%\\\')\';

    return $where ;
}, 10, 2 );

结束