custom field - Allow only one post with specific meta value

I'm using a custom meta field, to specify which post will appear as a featured one in the front page.This meta fiel

I'm using a custom meta field, to specify which post will appear as a featured one in the front page.

This meta field is a true/false value, declared through ACF.

I want this condition to only be applied to one post, i.e. when the user declares a post as "featured", and saves it, all the other ones (theoretically only the last one) that have this meta value checked, should be turned "off".

To achieve this, I've declared a function attached to the "save_post" action, that turns to "false" this specific post meta value, for the older featured posts.

This is my approximation, but there's something that I'm missing, because it is not working at all.

function only_one_agenda_featured( $post_id ) {

    // If this isn't a 'agenda' post, don't update it.
    if ( 'agenda' != $post->post_type ) {
        return;
    }

    // Stop when it is an autosave
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
        return;
    }

    // Prevent quick edit from clearing custom fields
    if (defined('DOING_AJAX') && DOING_AJAX) {
        return;
    }

    $post_meta_value = get_post_meta( $post_id, 'agenda_featured', TRUE );

    if ( $post_meta_value == '1' ) {
        $args = array(
            'meta_key'         => 'agenda_featured',
            'meta_value'       => '1',
            'post_type'        => 'agenda',
            'post__not_in'     => array($post_id),
            );
        $posts_to_update = get_posts( $args );
        foreach ( $posts_to_update as $post_to_update ) {
            update_post_meta( $post_to_update->ID, 'agenda_featured', '0', '1' );
        }
    }
}
add_action( 'save_post', 'only_one_agenda_featured' );

Any help will be appreciated.

I'm using a custom meta field, to specify which post will appear as a featured one in the front page.

This meta field is a true/false value, declared through ACF.

I want this condition to only be applied to one post, i.e. when the user declares a post as "featured", and saves it, all the other ones (theoretically only the last one) that have this meta value checked, should be turned "off".

To achieve this, I've declared a function attached to the "save_post" action, that turns to "false" this specific post meta value, for the older featured posts.

This is my approximation, but there's something that I'm missing, because it is not working at all.

function only_one_agenda_featured( $post_id ) {

    // If this isn't a 'agenda' post, don't update it.
    if ( 'agenda' != $post->post_type ) {
        return;
    }

    // Stop when it is an autosave
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
        return;
    }

    // Prevent quick edit from clearing custom fields
    if (defined('DOING_AJAX') && DOING_AJAX) {
        return;
    }

    $post_meta_value = get_post_meta( $post_id, 'agenda_featured', TRUE );

    if ( $post_meta_value == '1' ) {
        $args = array(
            'meta_key'         => 'agenda_featured',
            'meta_value'       => '1',
            'post_type'        => 'agenda',
            'post__not_in'     => array($post_id),
            );
        $posts_to_update = get_posts( $args );
        foreach ( $posts_to_update as $post_to_update ) {
            update_post_meta( $post_to_update->ID, 'agenda_featured', '0', '1' );
        }
    }
}
add_action( 'save_post', 'only_one_agenda_featured' );

Any help will be appreciated.

Share Improve this question asked Nov 19, 2015 at 11:44 CapiedgeCapiedge 7881 gold badge7 silver badges17 bronze badges
Add a comment  | 

3 Answers 3

Reset to default 2

I want this condition to only be applied to one post, i.e. when the user declares a post as "featured", and saves it, all the other ones (theoretically only the last one) that have this meta value checked, should be turned "off".

You might then try to save the one and only featured post ID as an option instead.

Then you don't need to pollute the post meta table with multiple false values.

The first problem is that $post is not in scope in your callback. You need to alter the code to pull that in:

function only_one_agenda_featured( $post_id, $post ) {
  // ...
}
add_action( 'save_post', 'only_one_agenda_featured' ,10, 2);

Given that change, things should work better, but the code is overly complicated. Unless you need a history of old agenda_featured posts, all you need to do is delete the old field and then set the new one.

function only_one_agenda_featured( $post_id, $post ) {

    // If this isn't a 'agenda' post, don't update it.
    if ( 'agenda' != $post->post_type ) {
        return;
    }

    // Stop when it is an autosave
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
        return;
    }

    // Prevent quick edit from clearing custom fields
    if (defined('DOING_AJAX') && DOING_AJAX) {
        return;
    }

    if (!empty($_POST['agenda_featured']) && true == $_POST['agenda_featured']) {
        // delete
        delete_metadata ( 'agenda', null, 'agenda_featured', null, true );
        // and insert
        add_post_meta( $post_id, 'agenda_featured', true);
    }

}
add_action( 'save_post', 'only_one_agenda_featured' ,10, 2);

You can further simplify that by using a post-type specific hook:

3580            do_action( "save_post_{$post->post_type}", $post_ID, $post, $update );

Something like:

function only_one_agenda_featured( $post_id, $post ) {

    // Stop when it is an autosave
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
        return;
    }

    // Prevent quick edit from clearing custom fields
    if (defined('DOING_AJAX') && DOING_AJAX) {
        return;
    }

    if (!empty($_POST['agenda_featured']) && true == $_POST['agenda_featured']) {
        // delete
        delete_metadata ( 'agenda', null, 'agenda_featured', null, true );
        // and insert
        add_post_meta( $post_id, 'agenda_featured', true);
    }

}
add_action( 'save_post_agenda', 'only_one_agenda_featured' ,10, 2);

You could make the delete/save a bit more efficient with straight SQL but I stuck to Core functions like a good boy ;)

I apologize for resuming this old post, but I had a very similar need and investigated a bit on the answers posted here. Since I found a working way, let me share it.

My need was that only one post of type question had the first_question ACF flag checked. An answer suggests bringing it to options, but I needed that flag to control the visibility of other ACF fields.

The code I came up with for my solution is the following:

function update_first_question( $post_id ) {

    // If it's not the correct post type
    $post = get_post( $post_id );
    if ( $post->post_type != 'question' ) {
        return;
    }
    // Stop when it is an autosave
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
        return;
    }
    // Prevent quick edit from clearing custom fields
    if (defined('DOING_AJAX') && DOING_AJAX) {
        return;
    }

    // Check if the post being saved has first_question checked
    if (!empty($_POST['acf']['field_5d19b7f96cb7f']) && $_POST['acf']['field_5d19b7f96cb7f'] == TRUE) {

        // Delete 'first_question' meta from all posts
        delete_metadata ( 'post', NULL, 'first_question', NULL, TRUE );

        // Set 'first_question' meta for the post bring saved
        add_post_meta( $post_id, 'first_question', TRUE);

    }

}
add_action( 'acf/save_post', 'update_first_question', 5, 2);

What changes from the answers posted?

  • delete_metadata does not accept a custom post type, so it must be called with 'post'
  • When checking the $_POST array, you have to check the acf array with the field key in order to check its value
  • Since we're working with ACF fields it's better to hook it to acf/save_post in order to have the ACF values in $_POST. The hooked function should have a priority less than 10, to work with the value BEFORE being saved.
  • The above hook does not provide $post, so it must be retrieved by $post_id

So to answer the question, let me elaborate from s_ha_dum's answer. What you need is the following:

function only_one_agenda_featured( $post_id ) {

    // If it's not the correct post type
    $post = get_post( $post_id );
    if ( $post->post_type != 'agenda' ) {
        return;
    }
    // Stop when it is an autosave
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
        return;
    }
    // Prevent quick edit from clearing custom fields
    if (defined('DOING_AJAX') && DOING_AJAX) {
        return;
    }

    // Check if agenda_featured is being checked 
    if (!empty($_POST['acf']['field_562100c6cd7ad']) && $_POST['acf']['field_562100c6cd7ad'] == TRUE) {
        // delete
        delete_metadata ( 'post', NULL, 'agenda_featured', NULL, TRUE );
        // and insert
        add_post_meta( $post_id, 'agenda_featured', TRUE);
    }

}
add_action( 'acf/save_post', 'only_one_agenda_featured' , 5, 2); 

It probably won't help the OP 3 years after, but I hope it will help someone! Have a nice day!

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745354729a4624047.html

相关推荐

  • custom field - Allow only one post with specific meta value

    I'm using a custom meta field, to specify which post will appear as a featured one in the front page.This meta fiel

    13小时前
    20

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信