Ask your WordPress questions! Pay money and get answers fast! (more info)

Update Post Status based on User, Meta, and Attachments WordPress

  • SOLVED

When certain types of users register a 'profile page' (cpt) is created for them. However, I only want the profile to be visible (published) if the user has met certain criteria.

Essentially, I am looking for a function that dynamically checks attributes of a cpt and set the post status based on the criteria. For now there are two basic criteria, if the cpt has atleast 1 attachment (image) and the user has atleast 1 published 'product' cpt.

I have found a couple pieces of code that may help accomplish this, but I haven't been able to piece them together

http://wordpress.stackexchange.com/questions/12512/how-to-update-page-status-from-publish-to-draft-and-draft-to-publish
http://wordpress.stackexchange.com/questions/53746/use-a-function-to-update-post-meta-based-on-other-post-meta

http://codex.wordpress.org/Function_Reference/wp_update_post

Answers (2)

2012-11-14

John Cotton answers:

How about this?

if ( ! wp_next_scheduled( 'update_cpt_status' ) ) {
wp_schedule_event( time(), 'hourly', 'update_cpt_status' );
}

function update_cpt_status() {

// Get a list of pending profiles
$pending_profiles = get_posts( array( 'post_type' => 'profile page', 'post_status' => 'draft' ) );
foreach( $pending_profiles as $pending_profile ) {
// Has the author published a product?
$products = get_posts( array( 'post_type' => 'product', 'post_status' => 'publish', 'post_author' => $pending_profile->post_author );

if( !empty($products) ) { // They've got a product
$images = get_posts( array( 'post_type' => 'attachment', 'post_status' => 'publish', 'post_parent' => $pending_profile->ID ) );

if( !empty($images) ) { // They've got attachments
$pending_profile->post_status = 'publish';
wp_update_post($pending_profile);
}
}
}
}
add_action( 'update_cpt_status', 'update_cpt_status' );


Kyle comments:

Would this work backwards? As in if the post is set to 'published' and then one day the user deletes all of the images, it will changes the post status back to draft? Likewise if the user deletes all of their products it changes it


John Cotton comments:

As it stands, no but it could be modified to do that.


John Cotton comments:

Did that answer your question?


Kyle comments:

Unfortunately, I was not able to modify it properly


Kyle comments:

Do you know of a way to do this that would check every time a user role updates anything, so every time an author adds an attachment, edits a post, adds a post, submits a form it does these checks?


John Cotton comments:

Sure, you just use the WordPress hooks.

So, for example, there are add_attachment and edit_attachment hooks which pass the post id. You'd need to use that to retrieve the post info and then run the code in the middle of the loop I gave you to do the work.

You can view an excellent database of all hooks here:

http://adambrown.info/p/wp_hooks/version/3.4

You just need to pick out the actions you want to react to, code accordingly. Not all of the hooks give the same info, though most will give a post id, so you could reuse a function once you've got it

eg


function check_post_update( $post_id ) {
$post = get_post($post_id );

// run the assessing/changing logic

}
add_action( 'edit_attachment', 'check_post_update' );
add_action( 'add_attachment', 'check_post_update' );


Kyle comments:

Okay I will try this and come back.


Kyle comments:

Okay this is what I had so far, but it did not work:

function check_post_update() {

global $user;

if (current_user_can('delete_posts')){

global $current_user, $post;
$checkposts = new WP_Query( array( 'author' => $current_user->ID, 'post_type' => 'guides' ) );
$checkpostid = $checkpostsposts->posts[0]->ID;

$imagecheck = get_children( array(
'post_parent'=> $checkpostid
));

if ($imagecheck = 0){
$rejectit = array();
$rejectit['ID'] = $checkpostid;
$rejectit['post_status'] = 'draft';
wp_update_post( $rejectit ); } else {

$approveit = array();
$approveit['ID'] = $checkpostid;
$approveit['post_status'] = 'publish';
wp_update_post( $approveit );

}

}
}

add_action( 'edit_attachment', 'check_post_update' );
add_action( 'add_attachment', 'check_post_update' );
add_action( 'delete_attachment', 'check_post_update' );
add_action( 'delete_attachment', 'check_post_update' );
add_action( 'delete_post', 'check_post_update' );
add_action( 'update_postmeta', 'check_post_update' );


John Cotton comments:

Well, for a start, you're missing a closing brace on the function.

Next: what's global $user?

Then - some of those hooks don't have $post id as the first parameter (eg update_postmeta) - you need to look at each and construct a function around that (including increasing the parameter value ie the postmeat one should bd

add_action( 'update_postmeta', 'check_post_update', 10, 4);

Finally, you don't say what doesn't work. However, I notice that the code you are using is nothing like the code I gave you. Using the code I gave you would be a good start!



Kyle comments:

Where is closing brace missing, please be more specific

My apologies about the improper global variable.

Okay, well in that event I'll revisit those other hooks later and just start with the ones you listed.

I'm not sure which code you gave me you are referring to, when your response was 'no but it could be modified' I went ahead and tried to modify it...

When I said it doesn't work I meant it didn't update post status


John Cotton comments:

The function doesn't seem to have a closing brace (by my count at least).

Get one or two hooks working and then proceed with the rest.

<blockquote> I went ahead and tried to modify it...</blockquote>
.. out of all existence!

The code I gave you only took things one way (as you'd asked). To do it the other way required pulling back all posts (not just draft) and then allowing for a switch. The reason I didn't suggest anything was that you hadn't said whether the first part was working. Do one thing at a time [should be] my motto.

So something like this:


// Get a list of pending profiles

$pending_profiles = get_posts( array( 'post_type' => 'profile page', 'post_status' => 'all' ) );

foreach( $pending_profiles as $pending_profile ) {
$new_status = 'draft'; // Set a fallback

// Has the author published a product?
$products = get_posts( array( 'post_type' => 'product', 'post_status' => 'publish', 'post_author' => $pending_profile->post_author );

if( !empty($products) ) { // They've got a product
$images = get_posts( array( 'post_type' => 'attachment', 'post_status' => 'publish', 'post_parent' => $pending_profile->ID ) );

if( !empty($images) ) { // They've got attachments
$new_status = 'publish';
}

}

if($new_status != $pending_profile->post_status) {
$pending_profile->post_status = $new_status;
wp_update_post($pending_profile);
}
}


But that deals with all posts. You've now moved on to doing just one post at a time....


Kyle comments:

I agree with the one thing at a time, that's why I had tried to boil it down to just the image check, sorry for destroying its existence. Its back now.

Thank you for helping to clarify everything. Okay, I tried this, it is kind of working. Note the closing ) is missing from $products. It is setting the status of the cpt as Draft everytime though, even if those other two criteria are met.

function check_post_update() {

// Get a list of pending profiles

$pending_profiles = get_posts( array( 'post_type' => 'guides', 'post_status' => 'all' ) );

foreach( $pending_profiles as $pending_profile ) {

$new_status = 'draft'; // Set a fallback

// Has the author published a product?

$products = get_posts( array( 'post_type' => 'product', 'post_status' => 'publish', 'post_author' => $pending_profile->post_author ));

if( !empty($products) ) { // They've got a product

$images = get_posts( array( 'post_type' => 'attachment', 'post_status' => 'publish', 'post_parent' => $pending_profile->ID ) );

if( !empty($images) ) { // They've got attachments

$new_status = 'publish';

}

}

if($new_status != $pending_profile->post_status) {

$pending_profile->post_status = $new_status;

wp_update_post($pending_profile);

}

}

}

add_action( 'edit_attachment', 'check_post_update' );
add_action( 'add_attachment', 'check_post_update' );


John Cotton comments:

<blockquote>It is setting the status of the cpt as Draft everytime though, even if those other two criteria are met.</blockquote>

Then the two get_posts need to be tweaked to the correct settings (ie if they returning results then the filtering isn't what you want).

It's hard to know what to change it to as I can't see the rest of your code or the output.

I would do a print_r on the two result sets and see what's in there that shouldn't be, then work backwards on the arguments to get_posts to get only what you want.


Kyle comments:

Okay, will do

2012-11-14

Francisco Javier Carazo Gil answers:

Ktrusak,

You can do a function inside a cron that check those condiction every X minutes or directly that is executed every time a post/CPT is inserted/updated.

Give me more details and I can do it.