更新:私はこの記事の最後にある選択した答えの実装を確認しました。
私は、時間減衰に加えて Redditの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; ?>
問題
このPHPコードの問題は、WordPressクエリがすでに作成されているため、投稿を古い順に返すということです。
pre_get_posts
の使い方やrequest
フックの使い方がわかりません。はい、私はドキュメンテーションを読んだことがありますが、私にとっては今、それはあまりにも高度になっています。データベース構造
PHPコードスニペットからわかるように、meta_valuesをテーブルwp_postmeta
に保存しています。実際のHotnessスコアはオンザフライで計算され、データベースには保存されません。これは非常に効率的ではなく、とりわけユーザーにとってリアルタイムではないためです。
私の実際の質問
Meta_valuesは式の一部にすぎないため、クエリをmeta_value
で並べ替えることはできません。並べ替え順序として、式の結果を使用します。
どのようにメインのWordPressクエリを変更してmeta_valuesを調べ、各投稿の人気度を計算し、それらの投稿を最も人気の高いものから最も人気のないものに戻すのですか。
選択した答えの私の実装
functions.php
に以下の2つの関数を追加しました。
// 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_valueになっており、ユーザーが投稿に賛成、反対票、ダウンロード、またはお気に入り(お気に入り)を追加するたびに更新されます。 _tjnz_hotness
の値は、最初は投稿の公開時刻(GMT)に基づいており、score
は0です。公開時刻は、投稿のUnix Epochタイムスタンプから、私の個人的なEpoch(ブログが開始された日付)を引いたものです。その数が何であっても、実際には関係ありません。単に_tjnz_hotness
の値を低くするだけです。私のブログを立ち上げた直後に投稿された投稿は0に近い値になります。
_tjnz_degrees
はページが読み込まれるたびに計算されます。このページは、ページがロードされたときのdegrees
値を計算するために関数tjnz_temperature()
を使用します。投稿からすべてのメタ情報を取得し、それを使って投稿の現在の気温を計算します。
hotness
とdegrees
の主な違いは、実際の投稿のソートにはhotness
が使用されることです。この値を増減すると、基本的にタイムライン上の投稿が他の投稿と比べてオフセットされます。 degrees
の値はこれに基づいていますが、投稿のリアルタイムの年齢を考慮に入れています。
基本的に、これが意味するのは、投稿のhotness
が変化しない場合、degrees
の値は実際には低下し始めるということです(1時間あたり0.1度、1日あたり2.4)。
log
base 6の設定もそれを可能にして、投稿を 'hot'に保つためにますます多くの投票が必要となるようにします。最終的には、それがもはや新しい投稿から勝つことができなくなるポイントがあるでしょう。私の式では、投稿が必然的に「コールド」になるまでに約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(); ?>
先日、私はこのようなものを作る方法を考えていました、私はあなたがsave_postsフィルタを必要とするだろうという理由で、あらゆる投票、保存または更新で更新される投稿メタ値としてhottnesを保存することをお勧めしますpre_get_postsとメタクエリのような順序で投稿を並べる
$query->set('meta_key'=>'hottnes');
$query->set('orderby'=>'meta_value_num');
$query->set('order'=>'DESC');
お役に立てれば。