如何通过部分元键查询帖子?


9

我有一个功能,可以将帖子的“喜欢”状态存储为帖子元。我想将“喜欢”与喜欢它的用户相关联,所以我设置了一个自定义字段“ like_status_ {user_id}”(其中{user_id}是当前登录用户的ID),我将其存储为0或1.因此,对于具有多个“点赞”的帖子,db中将有几个元数据设置如下:

'meta_key' = 'like_status_0'
'meta_value' = 1
'meta_key' = 'like_status_2'
'meta_value' = 1
'meta_key' = 'like_status_34'
'meta_value' = 1

....等等。

特定帖子可能有数千个赞。我如何运行查询,以显示其他人是否也喜欢该帖子?

我在想这样的事情:

$query = new WP_Query(array(
    'meta_key' => 'like_status_{user_id}',
    'meta_value' => 1,
));

我正在尝试向所有喜欢该帖子的人发送通知,当其他人喜欢该帖子时……例如,“嘿,其他人喜欢您喜欢的帖子。您应该去看看!” 但是我需要一种方法来找出是否有人喜欢该帖子,如果喜欢,他们会是谁,以便我通知他们。

如果不可能,您能否建议一种更好的方式将数据存储为post_meta,同时又保持快速更新帖子上单个用户的喜欢状态的效率?

Answers:


6

遗憾的是,使用时,您无法对值进行meta_query使用LIKE比较。我走这条路...meta_keyWP_Query

相反,如果您要维护状态关系(如发布元数据)而不是用户元数据和/或自定义表中的元数据,则可以使用其他两种选择。

选项1

  • 不需要修改您的元架构
  • 使用wpdb类执行自定义查询

例:

//when a user likes a post...
$current_user_id = get_current_user_id();
add_post_meta($current_user_id, "like_status_{$current_user_id}", 1, false);

//later in the request...
global $wpdb;

$results = $wpdb->get_results(
    "
    SELECT meta_key 
    FROM {$wpdb->prefix}postmeta 
    WHERE meta_key 
    LIKE 'like_status_%'
    ",
    ARRAY_N
);

$results = array_map(function($value){

    return (int) str_replace('like_status_', '', $value[0]);

}, $results);

array_walk($results, function($notify_user_id, $key){

    //apply to all users except the user who just liked the post
    if ( $notify_user_id !== $current_user_id ) {
        //notify logic here...           
    }

});

注意:如果需要,可以进一步简化逻辑。

选项2

  • 需要您更改元架构
  • 要求您将用户ID存储为元值
  • 允许您与WP_Query一起使用meta_query

选项2要求您将元密钥从更改like_status_{user_id}为通用名称,例如like_statusliked_by_user_id,而不是1针对密钥存储值而不是存储用户的ID作为值。

//when a user likes a post...
$current_user_id = get_current_user_id();
add_post_meta($current_user_id, "liked_by_user_id", $current_user_id, false);

//later in the request
$args = array(
    'post_type'  => 'post', //or a post type of your choosing
    'posts_per_page' => -1,
    'meta_query' => array(
        array(
            'key' => 'liked_by_user_id',
            'value' => 0,
            'type' => 'numeric'
            'compare' => '>'
        )
    )
);

$query = new WP_Query($args);   

array_walk($query->posts, function($post, $key){

    $user_ids = get_post_meta($post->ID, 'liked_by_user_id');

    array_walk($user_ids, function($notify_user_id, $key){

        //notify all users except the user who just like the post
        if ( $notify_user_id !== $current_user_id ) {

            //notify logic here...
            //get user e.g. $user = get_user_by('id', $notify_user_id);

        }

    });

});

1
现在是从5.1开始,下面是我的回答
K. Tromp

@ K.Tromp Huzzah!
亚当

请更新接受的答案以反映最新的WP功能或@ K.Tromp的答案标记为最新的答案
zumek

10

具体回答您的问题非常困难。第一部分很简单。我最近在stackoverflow上做了类似的事情

比较元密钥并精确匹配。WP_Query没有办法使用简单的参数来调整此行为,但是我们总是可以自我介绍一下,然后调整posts_where子句以LIKE对元键进行比较。

过滤器

这只是一个基本过滤器,请根据需要进行调整。

add_filter( 'posts_where', function ( $where, \WP_Query $q )
{ 
    // Check for our custom query var
    if ( true !== $q->get( 'wildcard_on_key' ) )
        return $where;

    // Lets filter the clause
    $where = str_replace( 'meta_key =', 'meta_key LIKE', $where );

    return $where;
}, 10, 2 );

正如你所看到的,当我们确立了新的自定义参数,过滤器仅触发wildcard_on_keytrue。当检查出来时,我们只需将=比较器更改为比较LIKE

对此,请注意,LIKE进行比较本质上比其他比较昂贵

查询

您可以按照以下方式简单查询您的帖子,以获取所有带有元键的帖子 like_status_{user_id}

$args = [
    'wildcard_on_key' => true,
    'meta_query'      => [
        [
            'key'   => 'like_status_',
            'value' => 1,
        ]
    ]
];
$query = new WP_Query( $args );

其他问题

自定义字段不会影响性能,您可以在此处阅读我关于此主题的文章。但是,令您感到困扰的是,您说每个帖子都可能有成百上千的赞。这会影响性能并缓存大量的自定义字段数据。它也可能会阻塞大量不必要的自定义字段数据,从而使数据库难以维护。

我不是非常喜欢将序列化数据存储在自定义字段中,因为不能通过序列化数据进行搜索或排序。但是,我建议将所有用户ID存储在一个自定义字段下的数组中。当用户喜欢帖子时,您只需使用用户ID更新数组即可。获取自定义字段数据并遍历ID数组并使用ID进行操作很容易。看看get_post_meta()

更新自定义字段也很容易。为此,您将需要研究 update_post_meta(),我不知道如何创建自定义字段,但update_post_meta()绝对是您要使用的东西。

如果自定义字段更新时需要发送电子邮件或推送通知,则可以使用以下挂钩。(请参阅update_metadata()上下文

结论

在我发布此内容之前,再次,在您走序列化路线之前,请确保您不需要按排序数据排序或在序列化数据内搜索特定数据。


1
感谢您对post_meta性能的解释!超级有用。
codecribblr

这应该是公认的答案,使用过滤器比使用自定义查询总是更好。另外,请注意,如果您使用的是get_posts而不是WP_Query,则需要传递prevent_filters => false否则它不会触发过滤器。要对meta键执行LIKE,还需要根据要进行类似搜索的类型,将%放在数组中键的前面和后面。
Earle Davies

如果要查询帖子,但以前缀排除包含帖子元键的所有帖子,该如何过滤呢?(例如,排除所有具有帖子元赞'my_prefix_'?的帖子
戈迪

6

从wordpress 5.1开始,现在可以使用元查询,例如: 在此处输入图片说明


下划线的转义似乎是此方法的问题,但否则,它看起来还不错。感谢突出显示。
杰克

2

如果以后要使用更详细的统计信息,功能等扩展此功能,则另一种选择可能是:自定义表

  • 优点:可以根据您的需求量身定制,并且可以对其进行索引以提高性能。

  • 缺点:更多工作

可能还存在使用自定义分类法的变通方法,由于对核心表进行了索引,因此与后元查询相比,该方法可以提供更好的查询性能。

我正在尝试向所有喜欢该帖子的人发送通知,当其他人喜欢该帖子时……例如,“嘿,其他人喜欢您喜欢的帖子。您应该去看看!” 但是我需要一种方法来找出是否有人喜欢该帖子,如果喜欢,他们会是谁,以便我通知他们。

不知道您在这里指的是哪种通知,但这会很快变得笨拙。

示例:一个喜欢〜1000个帖子的用户,每个帖子获得〜1000个赞,那么管道中只有该用户的100万条通知!如果这些是电子邮件通知,则主机提供商可能会不满意,并且用户会发疯。使用第三方电子邮件服务也可能会很昂贵。


我实际上每人每个帖子仅发送一次通知。因此,这比听起来要少-尽管很多。我尝试使用内置表的原因是,我希望能够在实际的应用程序中使用此数据在将来使用标准的WP REST API。
codecribblr

-1

根据WP_Meta_Query文档,您可以在WP_Querycompare参数中使用该参数meta_query。但是,您只能在value和之间进行比较,key因此您可能需要重新考虑如何构造它。

一个like参数看起来像这样:

$arguments = array(
    'meta_query' => array(
        array(
            'key' => 'foo',
            'value' => 'ba',
            'compare' => 'LIKE'
        )
    )
);

$query = new WP_Query($arguments);

鉴于您无法在上进行“喜欢”搜索,key建议您在用户元数据中添加喜欢的帖子,并对喜欢该帖子的用户进行WP_User_Query搜索:

$arguments = array(
    'meta_query' => array(
        array(
            'key' => 'liked_post',
            'value' => '<post_id>'
        )
    )
);

$users = new WP_User_Query($arguments);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.