0

I have noticed this becoming a trend with comments and now posts. I'm sure many sites (especially community ones) will implement this.

Here's exactly what I mean, click here: https://stackexchange.com/questions?tab=realtime

Posts appear in real time as soon as they are published.

There are also another version of this where the expand link appears with (1 question with the new activity). You can see this in action here if you wait for several seconds: https://superuser.com/

I'm wondering is there any way to do this on Wordpress? With my loop?

Right now my loop looks like this:

<?php 
// Limit query posts to the current day
// 
$period = $_GET["period"];
$day = $_GET["d"];
$year = $_GET["y"]; 
$args = array(
    'year' => (int) date($year),    
    'monthnum' => (int) date( 'M' ),    
    'day' => (int) date($day), 
    'date_query' => array(
        array(
            'after' => ($period), 
        )
    )
    
);

$query = new WP_Query( $args );

// The Loop
while ( $query->have_posts() ) :
    $query->the_post();
        
get_template_part( 'template-parts/content', get_post_type() );
            
endwhile;
the_posts_navigation();

?>

I think this would help a lot of people. Thanks.

Will B.
  • 17,883
  • 4
  • 67
  • 69
robert0
  • 435
  • 2
  • 12
  • 2
    Websockets, aka Long time polling? – Honk der Hase Feb 28 '21 at 12:25
  • see: https://wordpress.stackexchange.com/questions/19501/how-do-i-use-ajax-to-show-the-new-posts-realtime-on-the-frontpage – Luuk Feb 28 '21 at 12:26
  • Several [various methods](https://stackoverflow.com/q/11077857/1144627) exist currently; Polling, Comet, [HTTP/2 Server Push](https://en.wikipedia.org/wiki/HTTP/2_Server_Push), SSE. Do you have a specific issue with one of those approaches? Otherwise the question is not really definitively answerable. – Will B. Feb 28 '21 at 22:48

1 Answers1

1

There are many ways to do that, you can use WebSockets (which is the best option) to send an event to each client when a new post is made, and they will update the HTML on the page.

The other option is to implement with AJAX (not the best option, but is easier). Basically, it will send a request each X time to check if there's any update from the last request. If there are new posts, update the HTML with the content. I'll say below why this can not be the best option.

Through WebSockets

WebSockets is a huge area (support chart), and you should search some articles to understand how they work to implement your own logic. A very simple example would make use of Ratchet library to make the PHP part and Socket.io to the server.

You can use wp_insert_post hook to send a message with post details to all clients every time a new post is inserted:

function send_new_post( $post_id, $post, $update ) {
  foreach ($clients as $client) {
    // Sending title and url to each client connected
    $client->send(json_encode(array('title' => $post->post_title, 'url' => get_permalink( $post_id ))));
  }
}
add_action( 'wp_insert_post', 'send_new_post', 10, 3 );

Take a look at the Example Chat implementation with Ratchet.

Through AJAX

First of all, I do not recommend using AJAX to do this on a site with many (even not that many) clients, because you can easily overload your server making those requests every X seconds.

let timestamp = 0;
function get_updates(){
  let url = '?real_time=' + timestamp;
  let update = $.ajax({
      type: 'POST',
      url: url,
      async: false,
      dataType: 'json',
  }).complete(function(data){
    // Get the current timestamp to make the next call
    timestamp = data.timestamp;
    if (data.posts){
        $.each(data.posts, function(index, element) {
            $('.posts').append($('<div>', {
                text: element.title
            }));
        });
    }
    setTimeout(function(){get_updates();}, 10000); // 30 seconds
  });
}
get_updates();

The timestamp will be synchronized on the first call, to prevent a client with a different timezone from getting a different timestamp, preventing old posts from being shown twice.

Here's one basic example to return the posts. You probably should make some extra validation on the timestamp to prevent from showing a very older post or even add posts_per_page to do not show a lot of posts, causing a lot of stress to your server:

function get_real_time_posts(){
  if (!isset($_GET['real_time'])){
    return;
  }

  // Check if it is a valid timestamp
  if ( !((string) (int) $_GET['real_time'] === $_GET['real_time']) 
  || !($_GET['real_time'] <= PHP_INT_MAX)
  || !($_GET['real_time'] >= ~PHP_INT_MAX)) {
    return;
  }
  $time = intval($_GET['real_time']);
  
  if ($time == 0) {
    // First call to sync timestamps
    echo json_encode(array(
      'posts' => [],
      'timestamp' => time()
    ));
    die;
  }
  $args = array(
      'post_type' => 'post',
      'date_query' => array(
          'after' => date('Y-m-d H:i:s', $time)
      )
  );
  $query = new WP_Query( $args );
  $posts = array();
  foreach ($query->posts as $key => $value) {
    $post = array(
      'ID' => $value->ID,
      'title' => $value->post_title,
      'excerpt' => $value->post_excerpt
    );
    $posts[] = $post;
  }

  $result = array(
    'posts' => $posts,
    'timestamp' => time()
  );
  echo json_encode($result);
  die;
}
Lucius
  • 1,246
  • 1
  • 8
  • 21