0

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.

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.

  • As an option? Do you mean to save it as an option in the wp_options table? – Capiedge Nov 19 '15 at 16:31
  • yes, just store a single number in the wp_options table (via the options API), very simple to maintain @Capiedge – birgire Nov 19 '15 at 16:34
  • Maybe simple to mantain, but not easy to implement through the ACF control panel. Because I want to show this metabox in every single cpt while editing, not in an theme options section... – Capiedge Nov 19 '15 at 17:16
  • You wouldn't need ACF for this approach, you could check out the Codex example on how to add a metabox and then adjust it slightly with a single checkbox that stores the value in the options table. @Capiedge – birgire Nov 19 '15 at 17:46
0

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 ;)

  • OK @s_ha_dum, understood! but... before test it, let me ask you: where are you checking if this particular post has the meta value set as "true" by the user? – Capiedge Nov 19 '15 at 14:55
  • oops, sorry. I didn't. Too much hurry. Of course, you aren't checking either :) – s_ha_dum Nov 19 '15 at 14:57
  • @Capiedge : see the edit – s_ha_dum Nov 19 '15 at 15:03
  • seems to not work ... does not affect any of the posts declared as "featured". I checked the DB and still have the same values. Maybe "delete_metadata" is not being executed? – Capiedge Nov 19 '15 at 15:22
  • 1
    As I said, I'm declaring the custom field through ACF, so the $_POST value for this particular case is $_POST['acf']['field_562100c6cd7ad']. But still not working... – Capiedge Nov 19 '15 at 16:16

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.