web-dev-qa-db-fra.com

Quel est le moyen le plus efficace d’interroger les publications en fonction des visites et de la date du jour en cours?

Je suis sur le point de développer un morceau de code pour mon site afin d'afficher les publications les plus populaires de la journée datant de X jours. J'aimerais avoir votre aide pour y parvenir de la manière la plus efficace.

C’est ce que je prévois de faire. Dites-moi s’il existe un moyen plus efficace de le faire.

  1. Enregistrez chaque vue de publication dans une méta de publication qui n'existera que pour le jour actuel. Jetpack étant activé, je peux l’utiliser pour obtenir les vues de chaque message.

  2. Interrogez les messages (avec WP_query) par la méta de poste contenant les visites de la journée.

  3. Appliquer un filtre par date (pour obtenir des publications datant de X jours). Je peux donc choisir l’âge des messages. Par exemple, je peux afficher les publications les plus populaires datant d’au plus un mois. Les publications de plus d'un mois ne seront pas prises en compte pour la requête.

  4. Enregistrez la requête dans un transitoire qui sera mis à jour toutes les heures (la requête ne sera donc pas appelée à chaque fois que je devrai afficher les posts les plus populaires). Je veux que ce soit toutes les heures car je veux montrer aux visiteurs un nouveau contenu toutes les heures.

  5. Le lendemain, lorsque la publication est visitée par un utilisateur, la méta de cette publication est supprimée et une nouvelle est créée pour la journée en cours.

Remarque: j'ai des centaines de milliers de messages.

Si je manque quelque chose, s'il vous plaît faites le moi savoir.

5
Gixty

Je pense que vous pouvez améliorer les performances

  • enregistrer les informations d'affichage dans une seule option à la place de post meta
  • appliquer la date du filtre lors de la sauvegarde plutôt que lors de la récupération
  • créer le balisage et l'enregistrer dans un fichier transitoire au lieu d'enregistrer la requête (mise en cache de fragments)

Mise en oeuvre approximative dans une classe

class PopularPosts
{

  const OPT = 'myplugin_popular_posts';

  /**
   * After checking post date to see if save or not, increment a counter in a option
   * as an array where keys are post ids and values number of views
   */
  public function save(WP_Post $post)
  {
    if ( ! $this->shouldSave($post))
        return;
    $opt = get_option(self::OPT, array());
    if ( ! isset($opt[$post->ID]) ) {
       $opt[$post->ID] = 0;
    }
    $opt[$post->ID]++;
    update_option(self::OPT, $opt);
  }


  /**
   * Get markup from cache or rebuild it.
   * In latter case setup an action on shutdown to defer cache of the markup.
   * @return string
   */
  public static function getMarkup()
  {
    $key = self::OPT . date('Yz'); // change everyday
    $cached = get_transient($key);
    if ( ! empty($cached))
        return $cached; // if cache is available just output it

    $instance = new static;
    $markup = $instance->buildMarkup();
    if (empty($markup))
        return ''; // return without cache empty results

    add_action('shutdown', function() use($markup,$key) {
      set_transient($key, $markup, HOUR_IN_SECONDS);
    });

    return $markup;
  }


  /**
   * Get popular posts and return proper markup
   * @return string
   */
  public function buildMarkup()
  {
    $opt = get_option(self::OPT);
    if(empty($opt))
        return; // nothing to get and show

    $posts = $this->getPosts($opt); // obtain posts
    $out = '';

    $format = '<li><a href="%s">%s</a><span>(%d %s)</span></li>';

    foreach($posts as $post) { 
      $title = apply_filters('the_title', $post->post_title);
      $plink = get_permalink($post);
      $out .= sprintf($format, $plink, $title, $opt[$post->ID], __('views', 'txdmn'));
    }

    return '<ul class="popular_posts">' . $out . '</ul>';
  }


  /**
   * Return true if the posts is not older than X days, where X is filterable
   * @return boolean
   */
  private function shouldSave( WP_Post $post )
  {
    $max_old = apply_filters( 'myplugin_popular_posts_max_days', 31 );
    $ptime = DateTime::createFromFormat('Y-m-d H:i:s', $post->post_date);
    $now = new DateTime('now');

    return (int) $now->diff($ptime)->days <= (int) $max_old;
  }


  /**
   * Return X popular posts, where X number is filterable
   * @return array
   */
  private function getPosts($opt)
  {
    arsort($opt); // reverse order: more to less popular
    $num = apply_filters('myplugin_popular_posts_num', 5);
    $ids = array_keys(array_slice($opt, 0, $num));

    return (array) get_posts(array('post__in' => $ids));
  }

}

Usage

Pour mettre à jour les vues de vues :

add_action('shutdown', function() {
  if (is_single()) { // maybe check for post type using is_singular()
    $popularposts = new PopularPosts;
    $popularposts->save(get_queried_object());
  }     
});

Et pour afficher le balisage dans vos modèles:

<?= PopularPosts::getMarkup() ?>

Les pièges et les améliorations possibles

L'option de compteur devrait être réinitialisée tous les jours , le code pour cela n'est pas fourni ici, mais devrait être assez facile à implémenter.

En utilisant une lib comme WP-TLC-Transient , vous pouvez améliorer la méthode getMarkup en utilisant l’expiration logicielle et la mise à jour en arrière-plan. Quelque chose comme ça:

  public static function getMarkup()
  {
    $key = self::OPT . date('Yz'); // change everyday

    return tlc_transient( $key )
      ->updates_with(array(new static, 'buildMarkup'))
      ->expires_in(HOUR_IN_SECONDS)
      ->get();
  }

Notez que je ne suis pas familier avec Jetpack, donc je ne sais pas comment obtenir des statistiques de post à partir de celui-ci. Par souci de simplicité, j'ai utilisé un crochet sur 'shutdown' pour incrémenter simplement le compteur dans l'option. Ce n'est pas idéal car de cette façon, le compteur est incrémenté même si un utilisateur vient d'actualiser la page ... bien sûr, vous pouvez l'améliorer.

Notez s'il vous plaît

Le code est complètement non testé .

3
gmazzap