0

Question

I want to cancel pending_to_published actions: Posts that match certain criteria should that go from pending to published should stay pending.

(Alternatively, I need a to make add an "Approve" button to posts of a certain taxonomy, if that's easier)

Context

A WP installation has a portfolio tax, of which posts are automatically created using a Gravity Form. These posts are saved with the status of "pending".

These posts have a ZIP file associated with them. When a user submission (portfolio post) is approved (published), the ZIP is unpacked and processed.

Doing this on the main HTTP server makes it lag or crash if multiple submissions are approved in a short period of time.

To fix this, the ZIP processing script has been rewritten and moved to another EC2 instance (the site is on AWS). The idea is to have a WP plugin that would move the ZIP file to a queue directory, and use sockets to tell the other server to start processing it's queue.

There are two ways to go about this:

  • Hook onto the pending_to_published action and cancel the change.
  • Add a button just for this

...which brings me to my initial question.

1 Answer 1

0

This is not a full solution, it is an idea for the method to proceed with.

First of all, you hook into pending_to_publish action and, instead of processing the zip file, you save its path on a transensient. This transient is an array of all the zip files that are approved and not processed.

Code maybe explain better than words:

add_action( 'pending_to_publish', 'put_zip_in_queue' );

function put_zip_in_queue( $post ) {  
  // I put post in draft status, so until zip is processed the post is not visible
  $postarr = array('ID' => $post->ID, 'status' => 'draft');
  wp_insert_post($postarr);
  $zip_path = get_the_zip_path( $post ); // this function is up to you ;)
  $queue = (array)get_transient('zip_queue');
  $queue[] = $zip_path;
  set_transient('zip_queue', $queue);
}

After that

  1. Set Cron in the second EC2 instance to call via sokets a script on first instance that check the 'queue_on_hold' transient, if it's empty check the 'zip_queue' transient, if not empty, get the first path in queue and pass it via sockets to the second EC2 instance. After a successfully socket send, the same script save the transient 'queue_on_hold' so if the second instance call again none is done:

    function respond_to_cron_call() {
       // allow comunication only from the second ec2 instance checkin its IP
       if ( $_SERVER['REMOTE_ADDR'] != 169.254.169.253) return;
       // server must also pass a key as second security layer
       if ( ! isset($_POST['key']) || hash('sha256', $_POST['key']) != $mystoredkey) return;
       if ( get_transient('queue_on_hold') ) return;
       $queue = (array)get_transient('zip_queue');
       if ( $queue[0] ) {
         // function up to you
         $send = send_socket_to_second_ec2_instance( $queue[0] ); 
         if ( $send ) {
           set_transient('queue_on_hold', $queue);
         }
       }
    }
    
  2. the second EC2 instance receive the socket with the path and process it. When completed, send a socket back to first instance with the status of processing:

    function my_super_awesome_zip_process_on_ec2_instance() {
      // allow comunication only from the first ec2 instance checkin its IP
       if ( $_SERVER['REMOTE_ADDR'] != 169.254.169.254) return;
       // server must also pass a key as second security layer
       if ( ! isset($_POST['key']) || hash('sha256', $_POST['key']) != $mystoredkey) return;
      ..
      ...
      send_socket_to_first_ec2_instance(); // function up to you
    }
    
  3. the first instance receive the status, and if ok, update the 'zip_queue' deleting the file just processed; set the related post to published (because is still in draft); delete the transient 'queue_on_hold'

    function respond_to_status( $status ) {
       // allow comunication only from the second ec2 instance checkin its IP
       if ( $_SERVER['REMOTE_ADDR'] != 169.254.169.253) return;
       // server must also pass a key as secon security layer
       if ( ! isset($_POST['key']) || hash('sha256', $_POST['key']) != $mystoredkey) return;
       if ( $status != 'complete' ) return;
       delete_transient('queue_on_hold')
       $queue = (array) get_transient('zip_queue');
       $postid = get_post_from_zip_path(queue[0]); // up to you
       unset(queue[0]);
       set_transient('zip_queue', $queue);
       $postarr = array('ID' => $postid, 'status' => 'publish');
       wp_insert_post($postarr);
    }
    

Now zip is processed, post is published and everithing ok. :) On next Cron run the process starts again.

How many often run the Cron is up to you, a lot depends on how long zip process takes, if you want you can also set different frequencies: e.g. every 5 minutes night time, every 15 minutes day time...

Hope it helps.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.