web-dev-qa-db-fra.com

Utilisation de la base de données meta_values ​​pour calculer une nouvelle commande à l'aide de pre_get_posts ou d'un hook 'request'

UPDATE: J'ai élaboré la mise en œuvre de la réponse sélectionnée au bas de ce message.

J'implémente un algorithme de tri basé sur l'algorithme de hotness de Reddit , en plus d'une décroissance temporelle (comme Hacker Algorithme d'actualités d'actualités ).

Le code dont je suis actuellement satisfait est le résultat d'essais et d'erreurs dans certaines feuilles d'Excel et autres. Voici le code de travail en 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; ?>

Le problème

Le problème avec ce code PHP est que la requête WordPress a déjà été effectuée, elle renvoie donc les publications dans un ordre anti-chronologique.

  • Je veux trier les messages par score 'Hotness'
  • Je ne souhaite pas utiliser un nouvel objet WP_Query ou query_posts (), car cela perturberait la requête d'origine, ce qui entraînerait des interactions inutiles avec la base de données. Le site est assez occupé et j'héberge plus d'un millier de messages maintenant.
  • Je ne sais pas comment utiliser pre_get_posts ou utiliser le crochet request. Oui, j'ai lu la documentation, mais pour moi, cela devient trop avancé maintenant.

La structure de la base de données

J'enregistre des méta-valeurs dans la table wp_postmeta, comme vous pouvez le constater dans mon extrait de code PHP. Le score Hotness réel est calculé à la volée et n'est pas enregistré dans la base de données car il ne serait pas très efficace et surtout pas en temps réel pour les utilisateurs.

Ma question actuelle

Je ne peux pas trier la requête par meta_value, car les méta-valeurs ne constituent qu'une partie de l'équation. Je veux utiliser le résultat de l'équation comme ordre de tri.

Comment puis-je modifier la requête WordPress principale pour consulter les méta_valeurs, calculer chaque publication en temps réel et renvoyer ces publications de la plus chaude à la plus froide?

Ma mise en œuvre de la réponse choisie

Dans functions.php j'ai ajouté les deux fonctions suivantes.

// 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 est maintenant une méta_valeur pour chaque publication publiée et sera mise à jour chaque fois qu'un utilisateur votera, obtiendra une évaluation négative, téléchargera ou favoris (cœur) une publication. La valeur de _tjnz_hotness est initialement basée sur l'heure de publication (GMT) de la publication avec une variable score de 0. L'heure de publication est basée sur l'horodatage Unoch Epoch de la publication, moins mon époque personnelle (date de lancement de mon blog). Peu importe le nombre, cela rend la valeur _tjnz_hotness inférieure. Un article publié juste après le lancement de mon blog aura une valeur proche de 0.

_tjnz_degrees est calculé à chaque chargement de page. La page utilise la fonction tjnz_temperature() pour calculer la valeur degrees au moment du chargement de la page. Il récupère toutes les méta-informations de la publication et les utilise pour calculer la température actuelle de la publication.

La principale différence entre hotness et degrees est que hotness est utilisé pour le tri réel du courrier. Augmenter/diminuer cette valeur permet de compenser la publication sur une chronologie, par rapport aux autres publications. La valeur degrees est basée sur cela, mais elle prend en compte l’âge en temps réel d’une publication.

Cela signifie essentiellement que si la variable hotness d'un message ne change pas, la valeur degrees commence réellement à chuter (0,1 degré par heure, 2,4 par jour).

La configuration de la log base 6 fait également en sorte que de plus en plus de votes positifs sont nécessaires pour que le message reste à jour. Finalement, il y aura un moment où il ne pourra tout simplement plus gagner de nouveaux messages. Avec ma formule, il faut environ 5 à 7 jours à un message pour qu'il devienne inévitablement "froid".

Sur ma page personnalisée, je liste les publications de la manière suivante (il s’agit d’une sortie de débogage, aucun contenu de publication n’a encore été affiché).

<?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(); ?>
2
Marc Dingena

L'autre jour, je pensais comment faire quelque chose comme ça, je recommanderais de sauvegarder les bombes comme une méta-valeur post, qui est mise à jour à chaque vote, sauvegarde ou mise à jour, pour cela vous aurez besoin du filtre save_posts et vous pourrez ensuite obtenir les messages commandés avec pre_get_posts et une méta-requête quelque chose comme

$query->set('meta_key'=>'hottnes');
$query->set('orderby'=>'meta_value_num');
$query->set('order'=>'DESC');

J'espère que cela t'aides.

2
Poxtron