1

I've built a system where I have 2 options - lifespawn of draft and lifespawn of published post (integer which marks days).

If post is being published, exact date-time of publish is saved as postmeta, also lifespawn is added to that time and that value is saved to database as expiration date-time, same thing with draft (a.k.a when post is being saved).


My current system is ran like this:

  • I've set up a server cron which runs at night in every 24h

  • All published posts are being queried
  • Publish date-time metadata is retrieved from database in while loop
  • That time is compared with current time in if statement
  • If time has passed, change post status to draft

  • All draft posts are being queried
  • Draft date-time metadata is retrieved from database in while loop
  • That time is compared with current time in if statement
  • If time has passed, delete post
  • All attached images to the post are also queried and deleted

Im super worried that this system / server fails hard if posts amount is 10 000 - 15 000 or even few thousand. It's important that posts (especially published) that has exceeded the time, are taken down.

What other options do I have?


Ideas:

  • Trigger the date-time "check" for certain amount of older posts in random queries that users do anyway? - longer loading times for users..
  • Trigger the date-time "check" if single-post is being visited and do it one-by-one? - queries still retrieve and echo posts if people are quering it in exact same time which leads to 404s and disappointment.
  • Somehow split all posts and do it in chunks? - I could use 'offset' to split posts to groups and do it in smaller chunks but it doesn't work if page_per_page is set to -1

Update:

I've listened your advices and I've tried to query by "expiry date":

  • It seems to work.. I changed the cronjob interval and give it a try for few rounds
  • Is there a workarounds for formating date? if statement doesn't seem to work otherwise
  • Almost same code for drafts, only that I delete draft if time is up
  • I also imagine this would be better to run in every 1 hour to avoid big amounts, right?

//Current date-time
$now = date( 'Y-m-d H:i:s' ); //Let's say it's 2015-12-24 21:00:00 (9PM)

//Get all published posts that are over the deadline
$published_posts = new WP_Query( array(
    'posts_per_page'    => -1,
    'post_type'         => 'my-post',
    'post_status'       => 'publish',
    'meta_query' => array(
        array(
            'key'     => 'post_publish_deadline', //string e.g 2015-12-24 15:00:00 (3PM)
            'value'   => $now,
            'type'    => 'DATETIME',
            'compare' => '<=',
        )
    )
));

while( $published_posts->have_posts() ) {
    $published_posts->the_post();

//Get postmeta deadline and format it for if statement
$publish_deadline = get_post_meta( get_the_ID(), 'post_publish_deadline', true );
//If statement doesn't seem to work without this step
$format_publish_deadline = date( 'Y-m-d H:i:s', strtotime( $publish_deadline ) );

//Check if it exists just in case
if( !empty( $format_publish_deadline ) ) {

     //Additional check if time for that guy is over just in case
     if( $format_publish_deadline < $now ) {

         //Change post status to draft
         wp_update_post( array( 'ID' => get_the_ID(), 'post_status' => 'draft' ) );

         //Get lifespawn option
         $draft_to_delete_lifespawn = $my_option[ 'draft-lifespawn' ];   

         //Build a new draft expiration date-time -> now + lifespawn in hours
         $draft_deadline = date( 'Y-m-d H:i:s', strtotime( $now . ' + ' . $draft_to_delete_lifespawn . ' hours' ) );            

         //Save new draft expiration date-time
         update_post_meta( $post->ID, 'post_draft_deadline', $draft_deadline );
     }
}

} //END while
wp_reset_postdata();
7
  • Why are you querying all posts? Just pull the ones with dates past a certain age.
    – s_ha_dum
    Commented Dec 24, 2015 at 2:17
  • These dates are saved as strings to database similar to this: 2015-12-24 04:01:02, can I query by this? If I make the comparison, I format date-time that way: date( 'Y-m-d H:i:s', strtotime( $draft_deadline ) ); Or should I save them to database in other format which would be queriable?
    – N00b
    Commented Dec 24, 2015 at 2:21
  • That is a queryable format. You have Year-Month-Day-Hour-Minute-Second. Ordinary comparison actually works on that. Give it a shot. Plus it is a MySQL date format. You can do calculations using MySQL Core functions Should you use it? I prefer unixtime. You usually need to convert anyway to do anything interesting.
    – s_ha_dum
    Commented Dec 24, 2015 at 2:34
  • Can I query it using WP_Query or do I have to write my own SQL? Im guessing that I cannot use "older than this" with WP_Query, at least I haven't seen any examples and codex doesn't seem to have any explenations on this.
    – N00b
    Commented Dec 24, 2015 at 2:39
  • Ordinary comparison operators work on that format AKA: <,>,=, etc. It should be very simple. Please write some code and give it a try. If it doesn't work you will need some filters on the query.
    – s_ha_dum
    Commented Dec 24, 2015 at 2:40

1 Answer 1

2

You can improve by storing the "expiry" time of post as a meta instead of the publish time. This way you can query for posts with meta which is smaller then the current time and draft them, no need to loop over all posts.

Drawback is that you will have to decide how to handle changes to lifespawn time, just ignore this edge case or adjust all posts.

5
  • will try it much later (if will not forget :( ) ping me on "the loop" chat if I didn't add it by tomorrow. Commented Dec 24, 2015 at 14:26
  • Thanks, I've managed to code it, I would appriciate if you take a slight peak.
    – N00b
    Commented Dec 24, 2015 at 17:11
  • Instead of datetime I would use just an integer that is the result of time() as I more comfortable with integers but I don't see any obvious problem with your code. Commented Dec 24, 2015 at 17:41
  • Thank you. I hope this code doesn't fail me when post amounts are getting very very big. I think that I should set this cronjob to run in every hour to avoid big amounts of posts to process in one round.
    – N00b
    Commented Dec 24, 2015 at 17:45
  • It basically delegates your initial loop to the DB which should be faster by an order or two. If you wan to be safe don't try to handle everything in one go but split it into chunks, lets say every hour 1k posts with offset hour*1000 Commented Dec 24, 2015 at 18:05

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.