2

My goal is this:

I've added an additional metabox to my post page. Within this metabox there are multiple checkboxes. Each checkbox is associated with a person's name. The idea is that, if a person is featured in the post, I'll check the box associated with their name. For each checked box, an image of each person will appear in a pre-determined div in the single.php. As more checkboxes are checked, the images are still contained within this div but become thinner with the help of the css flexbox.

Metabox

My problem is this:

As it stands now, the checkboxes do nothing. Even if I check them, then update the post, they do not remain checked. This is obviously an issue with my code. I also need a way to set an image for each person. Much like the way you'd set the featured image for a post, but for each person on this checkbox list. I then need each checked box to cause an echo of HTML. This HTML will be the same for each person, but will contain different images dependant on the boxes checked.

Takes a moment to catch breath...

I'm very sorry for this lengthy explanation, but this has been destroying my brain all week...

My code for the metabox is as follows. It was copied from a template that someone was kind enough to post. I don't necessarily understand it all, but sometimes I find if easier to learn if I'm given the solution, then work back and figure out how it all works.

// Featured People Meta

add_action( 'add_meta_boxes', 'add_custom_box' );

function add_custom_box( $post ) {

add_meta_box(
        'Meta Box', // ID, should be a string.
        'Featured People', // Meta Box Title.
        'people_meta_box', // Your call back function, this is where your form field will go.
        'post', // The post type you want this to show up on, can be post, page, or custom post type.
        'side', // The placement of your meta box, can be normal or side.
        'core' // The priority in which this will be displayed.
    );

}

function people_meta_box( $post ) {

// Get post meta value using the key from our save function in the second paramater.
$custom_meta = get_post_meta($post->ID, 'people-meta-box', true);
?>

<input type="checkbox" name="people-meta-box[]" value="Bob" <?php if(isset($_POST['people-meta-box']['bob'])) echo 'checked="checked"'; ?>  /> Bob <br>
<input type="checkbox" name="people-meta-box[]" value="Bill" <?php if(isset($_POST['people-meta-box']['bill'])) echo 'checked="checked"'; ?>  /> Bill <br>
<input type="checkbox" name="people-meta-box[]" value="Steve" <?php if(isset($_POST['people-meta-box']['steve'])) echo 'checked="checked"'; ?> /> Steve <br>

// Save

<?php   

}

add_action( 'save_post', 'save_people_meta_box' );

function save_people_meta_box(){

global $post;

// Get our form field
if(isset( $_POST['people-meta-box'] )) :

    $custom = $_POST['people-meta-box'];

     // Update post meta

     foreach($ids as $id){
      update_post_meta($id, 'people-meta-box', $custom[$id]);
     wp_set_object_terms( $id,  $custom[$id], 'people' );
     }

endif;

}

I'm VERY new to WordPress and PHP in general, so this could have been answered before, but I could have overlooked it as my understanding of this subject may not have been sufficient to apply the solutions given to others, to my work.

4
  • 1
    Perhaps this article may help you. Commented Dec 4, 2014 at 16:11
  • 1
    there are no POST values when you render your meta box in people_meta_box function, your ifs should be checking the value of the saved meta data.
    – Milo
    Commented Dec 4, 2014 at 16:38
  • @Milo Sorry, I don't understand what you mean. Are you saying there should be POST values, or there shouldn't?
    – Bryce
    Commented Dec 5, 2014 at 4:26
  • Have you tried the Advanced Custom Fields plugin? It is one of the most widely used (and free) plugins in the Wordpress repository and does exactly what you're after (and more) without having to do all that custom coding. Just a thought.
    – Eckstein
    Commented May 2, 2015 at 3:07

2 Answers 2

2

I was racking my brains out with this too and was finally able to find a solution that works. This should work for you, I've tested quickly. I'll present it in 3 parts:

PART 1: ADD THE CUSTOM META BOX

add_action( 'add_meta_boxes', 'add_custom_box' );

    function add_custom_box( $post ) {
        add_meta_box(
            'Meta Box', // ID, should be a string.
            'Featured People', // Meta Box Title.
            'people_meta_box', // Your call back function, this is where your form field will go.
            'post', // The post type you want this to show up on, can be post, page, or custom post type.
            'side', // The placement of your meta box, can be normal or side.
            'core' // The priority in which this will be displayed.
        );
}

PART 2: DEFINE THE "CALLBACK" FUNCTION (spits out the html for the checkboxes)

  function people_meta_box($post) {
    wp_nonce_field( 'my_awesome_nonce', 'awesome_nonce' );    
    $checkboxMeta = get_post_meta( $post->ID );
    ?>

    <input type="checkbox" name="bob" id="bob" value="yes" <?php if ( isset ( $checkboxMeta['bob'] ) ) checked( $checkboxMeta['bob'][0], 'yes' ); ?> />Bob<br />
    <input type="checkbox" name="bill" id="bill" value="yes" <?php if ( isset ( $checkboxMeta['bill'] ) ) checked( $checkboxMeta['bill'][0], 'yes' ); ?> />Bill<br />
    <input type="checkbox" name="steve" id="steve" value="yes" <?php if ( isset ( $checkboxMeta['steve'] ) ) checked( $checkboxMeta['steve'][0], 'yes' ); ?> />Steve<br />

<?php }

PART 3: SAVE THE CHECKBOX VALUES

add_action( 'save_post', 'save_people_checkboxes' );
    function save_people_checkboxes( $post_id ) {
        if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) 
            return;
        if ( ( isset ( $_POST['my_awesome_nonce'] ) ) && ( ! wp_verify_nonce( $_POST['my_awesome_nonce'], plugin_basename( __FILE__ ) ) ) )
            return;
        if ( ( isset ( $_POST['post_type'] ) ) && ( 'page' == $_POST['post_type'] )  ) {
            if ( ! current_user_can( 'edit_page', $post_id ) ) {
                return;
            }    
        } else {
            if ( ! current_user_can( 'edit_post', $post_id ) ) {
                return;
            }
        }

        //saves bob's value
        if( isset( $_POST[ 'bob' ] ) ) {
            update_post_meta( $post_id, 'bob', 'yes' );
        } else {
            update_post_meta( $post_id, 'bob', 'no' );
        }

        //saves bill's value
        if( isset( $_POST[ 'bill' ] ) ) {
            update_post_meta( $post_id, 'bill', 'yes' );
        } else {
            update_post_meta( $post_id, 'bill', 'no' );
        }

        //saves steve's value
        if( isset( $_POST[ 'steve' ] ) ) {
            update_post_meta( $post_id, 'steve', 'yes' );
        } else {
            update_post_meta( $post_id, 'steve', 'no' );
        }  
}
0

Okay, so there are some tasks in this question.

First of all: You need a way to store associated persons and their photos. You specifically said that you would like to store them like featured images.

Enter "Custom Post Types"

Posts and Pages in Wordpress are organized as so-called "Post Types". There is a feature to register your own custom post types. The full documentation to register a custom post type can be found here, but i have written some sample code for you to register a custom post type that should be fitting for you.

The Reason i chose a custom post type is that you can easily extend your use-case to let visitors of your website visit a view of a single person and show additional information, like vita or some introduction to the person.

// Register Custom Post Type
function register_person_custom_post_type() {

    $labels = array(
        'name'                  => _x( 'Persons', 'Post Type General Name', 'text_domain' ),
        'singular_name'         => _x( 'Person', 'Post Type Singular Name', 'text_domain' ),
        'menu_name'             => __( 'Persons', 'text_domain' ),
        'name_admin_bar'        => __( 'Person', 'text_domain' ),
        'archives'              => __( 'Person Archive', 'text_domain' ),
        'attributes'            => __( 'Person Attributes', 'text_domain' ),
        'parent_item_colon'     => __( 'Parent Person', 'text_domain' ),
        'all_items'             => __( 'All Persons', 'text_domain' ),
        'add_new_item'          => __( 'Add new Person', 'text_domain' ),
        'add_new'               => __( 'Add New', 'text_domain' ),
        'new_item'              => __( 'New Person', 'text_domain' ),
        'edit_item'             => __( 'Edit Person', 'text_domain' ),
        'update_item'           => __( 'Update Person', 'text_domain' ),
        'view_item'             => __( 'View Person', 'text_domain' ),
        'view_items'            => __( 'View Persons', 'text_domain' ),
        'search_items'          => __( 'Search Persons', 'text_domain' ),
        'not_found'             => __( 'Not found', 'text_domain' ),
        'not_found_in_trash'    => __( 'Not found in Trash', 'text_domain' ),
        'featured_image'        => __( 'Featured Image', 'text_domain' ),
        'set_featured_image'    => __( 'Set featured image', 'text_domain' ),
        'remove_featured_image' => __( 'Remove featured image', 'text_domain' ),
        'use_featured_image'    => __( 'Use as featured image', 'text_domain' ),
        'insert_into_item'      => __( 'Insert into Person', 'text_domain' ),
        'uploaded_to_this_item' => __( 'Uploaded to this Person', 'text_domain' ),
        'items_list'            => __( 'Persons list', 'text_domain' ),
        'items_list_navigation' => __( 'Persons list navigation', 'text_domain' ),
        'filter_items_list'     => __( 'Filter Persons list', 'text_domain' ),
    );
    $args = array(
        'label'                 => __( 'Person', 'text_domain' ),
        'description'           => __( 'Persons to be attached to posts and pages', 'text_domain' ),
        'labels'                => $labels,
        'supports'              => array( 'title', 'thumbnail' ),
        'hierarchical'          => false,
        'public'                => true,
        'show_ui'               => true,
        'show_in_menu'          => true,
        'menu_position'         => 20,
        'show_in_admin_bar'     => true,
        'show_in_nav_menus'     => false,
        'can_export'            => true,
        'has_archive'           => false,
        'exclude_from_search'   => true,
        'publicly_queryable'    => false,
        'rewrite'               => false,
        'capability_type'       => 'page',
        'show_in_rest'          => false,
    );
    register_post_type( 'person', $args );

}
add_action( 'init', 'register_person_custom_post_type', 0 );

I chose the options to do the following stuff:

  • Don't have an archive page
  • Don't be searchable in the frontend
  • Don't have a single view
  • Don't have an Editor
  • Don't be in the REST-API

You can change these options later with the documentation or a tool like GenerateWP to make the persons viewable in the frontend.

Part Deux: Electric Meta-Boogaloo

Now we add our meta boxes and the saving them stuff. Registering the Metaboxes is pretty straightforward and you got it mostly right. However, because the use-case changed to a custom post type, we change some stuff up.

function my_persons_add_custom_box() {

    add_meta_box(
        'Meta Box', // ID, should be a string.
        'Featured People', // Meta Box Title.
        'my_persons_people_meta_box', // Your call back function, this is where your form field will go.
        'post', // The post type you want this to show up on, can be post, page, or custom post type.
        'side', // The placement of your meta box, can be normal or side.
        'core' // The priority in which this will be displayed.
    );
    //Repeat this for all the post types that you want to assign persons to, like "page" for instance
}
add_action( 'add_meta_boxes', 'my_persons_add_custom_box' );

function my_persons_people_meta_box( $post ) {
    wp_nonce_field( 'persons_awesome_nonce', 'persons_nonce' );  
    //this is a nonce, a special value that helps to prevent unauthorized changes
    $saved_associations = array();
    //we check if $post has an id
    if( isset( $post->ID ) ){
        $saved_associations = get_post_meta( $post->ID, '_attached_person_ids', true );
        if( ! is_array( $saved_associations ) ){
            $saved_associations = array();
        }
        //to correctly work here, we need $saved_associations to be an array. In the Array, each element is the ID of a person
    }
    $available_persons = get_posts(
        array(
            'post_type' => 'person',
            'posts_per_page' => -1,
            'order' => 'ASC',
            'orderby' => 'post_title'
        )
    );
    foreach( $available_persons as $available_person ){
        ?>
        <label>
            <input type="checkbox" name="associated_person[]" value="<?php echo $available_person->ID; ?>" <?php if( in_array( $available_person->ID, $saved_associations ) ){ ?>checked <? } ?>/>
            <?php echo get_the_title( $available_person->ID ); ?>
        </label>
        <?php
    }
}

function save_people_checkboxes( $post_id ) {
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
        //we dont want to save our metabox if the browser does an autosave
        return;
    }
    if ( !isset( $_POST['persons_nonce'] ) || ( isset ( $_POST['persons_nonce'] ) ) && ( ! wp_verify_nonce( $_POST['persons_nonce'], 'persons_awesome_nonce' ) ) ){
        //check the nonce. if it's not correct, don't save
        return;
    }
    if ( ( isset ( $_POST['post_type'] ) ) && ( 'page' == $_POST['post_type'] )  ) {
        //if this is a page, we only want to save if the current user can really edit this page
        if ( ! current_user_can( 'edit_page', $post_id ) ) {
            return;
        }    
    } else {
        if ( ! current_user_can( 'edit_post', $post_id ) ) {
            //if this is a post, we only want to save if the current user can really edit this post
            return;
        }
    }
    if( ! isset( $_POST['associated_person'] ) || empty( $_POST['associated_person'] ) ){
        //if there are no associated persons transferred, all the checkboxes are unchecked, which means we have to un-attach previously attached persons from this post
        delete_post_meta( $post_id, '_attached_person_ids' );
        return;
    }
    if( ! is_array( $_POST['associated_person'] ) ){
        //somebody transferred something other than an array of ids in our post field. we can't work with that
        delete_post_meta( $post_id, '_attached_person_ids' );
        return;
    }
    $new_meta = array();
    foreach( $_POST['associated_person'] as $associated_id ){
        //always sanitize your input!
        $id = absint( $new_meta );
        //only save it if its really a person
        if( 'person' == get_post_type( $id ) ){
            $new_meta[] = $id;
        }
    } 
    //is there something to save?
    if( ! $new_meta ){
        delete_post_meta( $post_id, '_attached_person_ids' );
        return;
    }
    //yay, we did it! Update the post meta with our new array!
    update_post_meta( $post_id, '_attached_person_ids', $new_meta );
}
add_action( 'save_post', 'save_people_checkboxes' );

So, how do i use this in my theme?

For the last part, we just need a function to show our persons images in your single.php or wherever. For this, we write a function:

function show_attached_persons( $post_id = null ){
    //if a post id was not given in the function call, just use the current post id that is in the loop
    if( ! $post_id ){
        $post_id = get_the_ID();
    }
    //now get the meta value
    $attached_persons = get_post_meta( $post_id, '_attached_person_ids', true );
    if( ! is_array( $attached_persons ) || is_empty( $attached_persons ) ){
        //no attached persons, nothing to do here
        return "";
    }
    $output = "";
    foreach( $attached_persons as $attached_person ){
        $person_post = get_post( $attached_person );
        if( ! $person_post || !( 'person' == get_post_type( $attached_person ) ) ){
            continue;
        }
        if( has_post_thumbnail( $attached_person ) ){
            //change image_size to your preferred image size, like thumbnail or medium
            //also, add whatever html markup you need per person in your output
            $output.= get_the_post_thumbnail( $attached_person, 'image_size' );
        }
    }
    return $output;
}

All you now have to do in your single.php is do an echo show_attached_persons() at the place where your attached persons should be displayed, and badabing badaboom you're done!

I didn't test this, but it should work!

Happy Coding!

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.