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!
POST
values when you render your meta box inpeople_meta_box
function, yourif
s should be checking the value of the saved meta data.