使用数据库META_VALUES通过PRE_GET_POST或‘REQUEST’挂钩计算新的POST订单

时间:2013-03-09 作者:Marc Dingena

UPDATE: I have worked out my implementation of the selected answer at the bottom of this post.

我正在实现一个基于Reddit\'s hotness algorithm, 除了时间衰减(如Hacker News hotness algorithm).

我目前满意的代码是在一些Excel工作表和诸如此类的工作表中反复尝试的结果。以下是PHP中的工作代码:

<?php get_header();
$timenow = time() - 1211380200; // this is my custom Epoch time, it translates to when my first WP post was made ?>

<?php
if ( have_posts() ) : while ( have_posts() ) : the_post(); 

$hearts = get_post_meta($post->ID, \'_tjnz_hearts\', true);
$plays      = get_post_meta($post->ID, \'_tjnz_deals_plays\', true);
$downloads  = get_post_meta($post->ID, \'_tjnz_deals_downloads\', true);
$ups        = get_post_meta($post->ID, \'_tjnz_temperature_upvotes\', true);
$downs      = get_post_meta($post->ID, \'_tjnz_temperature_downvotes\', true);
$date       = get_post_time(\'U\', true); // fetches the GMT postdate of post in Unix format

$score = ( ( $hearts * 2 ) + $plays + $downloads + $ups ) - $downs;
$order = log( max( abs( $score ), 1 ), 6 );
$seconds = $date - 1211380200;
if( $score > 0 ) { $sign = 1;   } elseif( $score < 0 ) { $sign = -1; } else { $sign = 0; }
$hotness = round( $order + ( ( $sign * $seconds ) / 336000 ), 7 );
$degrees = round( ( $order * ( $sign * 32 ) ) + ( ( -4 * ( $timenow - $seconds ) ) / 336000 ), 7 ); ?>
        <p>
            <?php the_title(); ?> <?php echo $post->ID; ?><br />
            <?php echo \'hearts: \' . $hearts . \'<br />\';
            echo \'plays: \' .$plays . \'<br />\';
            echo \'dls: \' .$downloads . \'<br />\';
            echo \'up: \' .$ups . \'<br />\';
            echo \'down: \' .$downs . \'<br />\';
            echo \'date: \' .$date . \'<br /><br />\';
            echo \'score: \' .$score . \'<br />\';
            echo \'order: \' .$order . \'<br />\';
            echo \'seconds: \' .$seconds . \'<br />\';
            echo \'timenow: \' .$timenow . \'<br />\';
            echo \'difference: \' .($timenow - $seconds) . \'<br />\';
            echo \'sign: \' .$sign . \'<br /><br />\';
            echo \'hotness: \' .$hotness . \'<br />\';
            echo \'degrees: \' .$degrees; ?><hr />
        </p>

<?php endwhile; else: ?>
<p><?php _e(\'Sorry, no posts matched your criteria.\'); ?></p>
<?php endif; ?>

The problem

这段PHP代码的问题是,WordPress查询已经完成,所以它只是按反时间顺序返回帖子。

我想按“热度”得分对帖子进行排序,我不想使用新的WP\\u查询对象或Query\\u posts(),因为这会影响原始查询,从而导致不必要的数据库交互。该网站相当繁忙,我现在正在托管一千多篇帖子pre_get_posts 或使用request 钩是的,我已经阅读了文档,但对我来说,它现在太高级了

The database structure

我正在表中保存meta\\u值wp_postmeta, 正如您可以从我的PHP代码片段中看到的那样。实际的热度分数是动态计算的,而不是保存到数据库中,因为这样做效率不高,最重要的是,对用户来说不是实时的。

My actual question

我无法对查询进行排序meta_value, 因为meta\\u值只是等式的一部分。我想使用result 作为排序顺序。

如何更改WordPress主查询以查看meta\\u值,计算每个帖子的热度,并将这些帖子从最热返回到最冷?

My implementation of the chosen answer

在里面functions.php 我添加了以下两个函数。

// add custom wp_postmeta when a new post is created
add_action( \'wp_insert_post\', \'tjnz_prepare_postmeta\' );
function tjnz_prepare_postmeta( $post_id ) {
    if ( !wp_is_post_revision( $post_id ) ) {
        $hotness = round( ( time() - 1211380200 ) / 336000, 7 );
        add_post_meta( $post_id, \'_tjnz_hearts\', 0, true );
        add_post_meta( $post_id, \'_tjnz_plays\', 0, true );
        add_post_meta( $post_id, \'_tjnz_downloads\', 0, true );
        add_post_meta( $post_id, \'_tjnz_upvotes\', 0.000, true );
        add_post_meta( $post_id, \'_tjnz_downvotes\', 0.000, true );
        add_post_meta( $post_id, \'_tjnz_hotness\', $hotness, true );
    }
}

// build an array of Hotness stats for post
function tjnz_temperature( $tjnz_post_id, $tjnz_timenow ) {
    $hearts     = get_post_meta($tjnz_post_id, \'_tjnz_hearts\', true);
    $plays      = get_post_meta($tjnz_post_id, \'_tjnz_plays\', true);
    $downloads  = get_post_meta($tjnz_post_id, \'_tjnz_downloads\', true);
    $ups        = get_post_meta($tjnz_post_id, \'_tjnz_upvotes\', true);
    $downs      = get_post_meta($tjnz_post_id, \'_tjnz_downvotes\', true);
    $hotness    = get_post_meta($tjnz_post_id, \'_tjnz_hotness\', true);
    $date       = get_post_time(\'U\', true);
    $score      = $hearts + $downloads + $ups - $downs;
    $log        = log( max( abs( $score ), 1 ), 6 );
    $seconds    = $date - 1211380200;
    if( $score >= 0 ) { 
        $sign = 1;
    } else { 
        $sign = -1;
    }
    $degrees    = round( ( $log * ( $sign * 32 ) ) + ( ( -9.6 * ( $tjnz_timenow - $seconds ) ) / 336000 ) + 10, 7 );
    //      round to 7 digits    positive/negative    -2.4 degrees/day      realtime post age       +10 free degrees

    return array(
        \'hearts\'    => $hearts,
        \'plays\'     => $plays,
        \'downloads\' => $downloads,
        \'ups\'       => $ups,
        \'downs\'     => $downs,
        \'score\'     => $score,
        \'hotness\'   => $hotness,
        \'degrees\'   => $degrees
    );
}
_tjnz_hotness 现在是每个已发布帖子的meta\\u值,并且将在用户每次对帖子进行上投票、下投票、下载或收藏夹(红心)时更新。的价值_tjnz_hotness 最初基于帖子的发布时间(GMT),并带有score 共0个。发布时间基于帖子的Unix Epoch时间戳,减去我的个人Epoch(我的博客发布的日期)。这个数字是多少并不重要,它只是让_tjnz_hotness 值较低。在我的博客发布后立即发布的帖子的值将接近0。

_tjnz_degrees 在每次页面加载时计算。页面使用函数tjnz_temperature() 要计算degrees 加载页面时的值。它从帖子中获取所有元信息,并使用它计算帖子的当前温度。

两者之间的主要区别hotnessdegrees, 是吗hotness 用于对邮件进行实际排序。增加/减少此值基本上会相对于其他帖子抵消时间线上的帖子。这个degrees 值基于此,但它考虑了帖子的实时时间。

本质上,这意味着如果一篇文章hotness 不会改变degrees 实际值开始下降(每小时0.1度,每天2.4度)。

设置log 基数6也使得需要越来越多的更新投票来保持帖子的“热门”。最终,它将无法再从更新的帖子中获胜。按照我的公式,一篇帖子要花5-7天的时间才能不可避免地变得“冷”。

在我的自定义页面上,我列出了如下帖子(这是一个调试输出,还没有显示实际的帖子内容)。

<?php
/*
Template Name: Hot
*/
get_header();
$timenow = time() - 1211380200; 
$hot_query = new WP_Query(
    array(
        \'post_status\' => \'publish\',
        \'post_type\' => \'post\',
        \'meta_key\' => \'_tjnz_hotness\',
        \'posts_per_page\' => 30,
        \'orderby\' => \'meta_value_num\',
        \'order\' => \'DESC\'
    )
);

if ( $hot_query->have_posts() ) : while ( $hot_query->have_posts() ) : $hot_query->the_post(); 
    $tjnz_temperature = tjnz_temperature( $post->ID, $timenow );
?>
    <?php the_title(); ?> <?php echo $post->ID; ?><br />
    <?php echo \'hearts: \' . $tjnz_temperature[\'hearts\'] . \'<br />\';
    echo \'plays: \' . $tjnz_temperature[\'plays\'] . \'<br />\';
    echo \'dls: \' . $tjnz_temperature[\'downloads\'] . \'<br />\';
    echo \'up: \' . $tjnz_temperature[\'ups\'] . \'<br />\';
    echo \'down: \' . $tjnz_temperature[\'downs\'] . \'<br />\';
    echo \'score: \' . $tjnz_temperature[\'score\'] . \'<br />\';
    echo \'hotness: \' . $tjnz_temperature[\'hotness\'] . \'<br />\';
    echo \'degrees: \' . $tjnz_temperature[\'degrees\']; ?><hr />

<?php endwhile; else : ?>
    <p>Oops, Post Not Found!</p>

<?php endif; get_footer(); ?>

1 个回复
最合适的回答,由SO网友:Miguel 整理而成

前几天,我在考虑如何制作这样的内容,我建议将hottnes保存为一个post meta值,该值在每次投票、保存或更新时都会更新,因为您将需要save\\u posts过滤器,然后您可以使用pre\\u get\\u posts和类似的meta查询来订购帖子

$query->set(\'meta_key\'=>\'hottnes\');
$query->set(\'orderby\'=>\'meta_value_num\');
$query->set(\'order\'=>\'DESC\');
希望这有帮助。

结束

相关推荐

Sort Posts Best Practice

我有一个自定义的帖子类型“属性”。这些属性帖子列在“Let属性”页面上。每个属性帖子都有各种自定义元数据,包括价格和卧室数量。属性最初将按原始wp查询集定义的顺序列出。然而,在页面顶部,我希望有链接,点击后将按价格、添加日期和卧室数量对帖子进行排序。这样做的最佳实践是什么?我见过有人建议将查询字符串添加到URL等,但希望得到一些可靠的建议提前感谢您的帮助约翰