0

I'm having a problem with a custom function. This function counts the post and assigns a number to that post. It then saves the number to a custom field and then updates the permalink to the post.

My problems are:

1). When a post is saved, it saves a post twice (Shows up as 2 revisions). I'm trying to find a way so that it saves it once.

2). I'm also trying to find a way for the function to work only once. I'm noticing that previous posts are getting edited and while they are staying the same, they do show up with lots of revisions. For example: If I have 5 posts, the first post will show up with 10 revisions.

Here's my code:

// opens a function
function updateNumbers( $post_id ){

// sets global 
global $pagenow;

// if current page is a new post and in the post CPT
if ($pagenow == 'post.php' &&  'post' == get_post_type()) {

    // counts all posts
    global $wpdb;
    $querystr = "SELECT $wpdb->posts.* FROM $wpdb->posts WHERE
    $wpdb->posts.post_status = 'publish' AND $wpdb->posts.post_type = 'post' ";
    $pageposts = $wpdb->get_results($querystr, OBJECT);
    $counts = 0 ;
    if ($pageposts):
    foreach ($pageposts as $post):
    $counts++;

    // saves the number to a custom field
    add_post_meta($post->ID, 'incr_number', $counts, true);
    remove_action('save_post', 'updateNumbers');
    wp_update_post(array('ID' => $post->ID,'post_name' => get_post_meta($post->ID,'incr_number', true)));
    endforeach;
    endif;
}}

// close the function and save
add_action('save_post', 'updateNumbers');
3

It duplicate because when you run the wp_update_post(), it will use the wp_insert_post() function and the action save_post will run again.

please use the filter wp_insert_post_data to filter the value before save. https://codex.wordpress.org/Plugin_API/Filter_Reference/wp_insert_post_data

Example:

function wpse309780_filter_post_data($data , $postarr) {
    $data['post_name'] = wp_count_posts( 'post' )->publish;
    return $data;
}

add_filter( 'wp_insert_post_data', 'wpse309780_filter_post_data' );
2

Always lean back on WordPress Codex.

In this case, you are using 'save_post' action hook, thus we can consult the WordPress Codex and WordPress Code Reference pages.

Just by checking these links, we can see that this action have 3 arguments which can be used in the function: $post_ID, $post, $update.

In order to use the last argument $update for example, we have to set $accepted_args parameter in the 'save_post' hook. This is the last digit so to say, in the action that you are declaring and modified action would look like this: add_action('save_post', 'updateNumbers', 10, 3);

Now we also see the digit "10" just before the last one - this is the priority that decides when will your action be fired.

So if we would like to fire our action earlier, we would modify our action: add_action('save_post', 'updateNumbers', 5, 3);

Looking at your function, there are many ways you could improve it. While the corer of your question is clear, there are a few ways that you could go about optimizing the function. Because currently, you are:

  1. Executing an action that is triggered whenever a post is saved or updated (that's good);

  2. In your function, you get all posts in the database (seems somewhat okay);

  3. You check whether there are any posts in the database with an if ($pageposts): (In some scenarios could be skipped, but let's keep it);

  4. Then you perform bellow actions for each post, that you found in database (yes, not just this one, but for each, so basically, when you are updating single post, you are actually updating all of the posts from your query and that's why you are getting multiple revisions generated for other posts as well - this is quite bad as you also expressed that you do not want that):

  5. You are updating your custom field with current $count value.

  6. You are removing your hooked function by removing 'save_post' action, which is great since you are calling 'wp_update_post' function that also would call 'save_post', and if you didn't remove your hooked function, it would result in infinite loop. However, you forgot to re-hook it after calling 'wp_update_post'.

  7. You are updating post slug with the value of custom meta field.

You should clarify a few things:

  • Are you re-using 'incr_number' custom field anywhere else or is it just to update the slug? If you are not using this custom field anywhere else, then you should get rid of it. Having in mind, that this custom meta field is exactly as your post slug, you should just get rid of it anyway and replace with the value of post slug wherever you need it. That is if you do not intend to change slugs after you initially set them to a number.

  • I see comment:

    // if current page is a new post and in the post CPT

Is your intention to update permalink only when the post is new? Then I wouldn't say your implementation is optimal for doing so. Actually, this is where you would use the third argument $update that this action offers.

This is how I would modify your function (however due to lack of information and without clear goal of your action, this may not be final).

// Update permalink of newly created Post
add_action('save_post', 'theme_save_post_number_to_slug', 12, 3);

function theme_save_post_number_to_slug($post_id, $post, $update) {

    $post_type = get_post_type($post_id);

    // terminate early if post type is not 'post' and if we are updating post object and not creating it.
    if ( "post" != $post_type && !$update )
        return;

    global $wpdb;
    $count = 0 ;

    // Fetches all posts with status 'publish' from the database
    $querystr = "SELECT $wpdb->posts.* FROM $wpdb->posts WHERE
    $wpdb->posts.post_status = 'publish' AND $wpdb->posts.post_type = 'post' ";
    $dbPosts = $wpdb->get_results($querystr, OBJECT);

    if ($dbPosts) {
        foreach ($dbPosts as $p):
            $count++;

            // saves the number to a custom field
            add_post_meta($p->ID, 'incr_number', $count, true);

            remove_action('save_post', 'theme_save_post_number_to_slug', 12, 3);
            wp_update_post(array('ID' => $p->ID, 'post_name' => get_post_meta($p->ID, 'incr_number', true)));
            add_action('save_post', 'theme_save_post_number_to_slug', 12, 3);

        endforeach;
    }

}

The function is still not perfect as I do not know what do you want to achieve, plus I want you to figure it out completely (that's how we grow as a developer).

Honestly, there are quite a few quirks that could be sorted out with a detailed explanation. You could even ask that yourself and then consult WordPress Codex.

I hope that I at least steered you to right way.

  • Thanks for the response but now it does triple revisions when saving. I'm looking into wp_insert_post – Gregory Schultz Jul 29 '18 at 19:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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