Notice: completely update code after OP update answer.
Assuming you want to update in front-end the taxonomy ‘post_tag’ (the standard tags) fro standard post and a taxonomy called ‘research-sections’ for a custom post type called ‘research’.
Probably you have to put the form in both single.php
and single-research.php
and in both you have to some stuff… because is always better having a DRY code, and related to WP is always better keep templates clean, I suggest you to put all the functional code in a plugin or in functions.php
and modify as less as possible the templates.
You need essentially 2 functions: one that output the form, another that saves data.
For the first you can create your own action, in this way in template only thing you need is a do_action
call.
For the function that saves data you can hook a standard WP action, like init.
The code:
add_action('init', 'frontend_term_assignment');
add_action('frontend_term_assignment_form', 'frontend_term_assignment_form');
function frontend_term_assignment() {
if (
! isset($_POST['term_assignment_post_id']) ||
! intval($_POST['term_assignment_post_id']) ||
! current_user_can('edit_posts', $_POST['term_assignment_post_id']) ||
! isset( $_POST['term_assignment_nonce'] ) ||
! wp_verify_nonce($_POST['term_assignment_nonce'], 'frontend_term_assignment')
) return;
$post = get_post( $_POST['term_assignment_post_id'] );
$taxonomy = null;
if ( $post->post_type == 'post' ) {
$taxonomy = 'post_tag';
} elseif ( $post->post_type == 'research' ) {
$taxonomy = 'research-sections';
}
if ( empty($taxonomy) || ! isset($_POST[$taxonomy]) ) return;
$terms = $_POST[$taxonomy];
wp_set_object_terms( $post->ID, $terms, $taxonomy, false);
}
function frontend_term_assignment_form() {
$post = get_queried_object();
if ( empty($post) || ! isset($post->ID) || ! current_user_can('edit_posts', $post->ID) ) return;
$taxonomy = null;
if ( $post->post_type == 'post' ) {
$taxonomy = 'post_tag';
} elseif ( $post->post_type == 'research' ) {
$taxonomy = 'research-sections';
}
if ( empty($taxonomy) ) return;
$tax_obj = get_taxonomy($taxonomy);
$args = array('orderby' => 'name', 'order' => 'ASC', 'hide_empty' => false );
$terms = get_terms($taxonomy, $args);
$post_terms = (array)wp_get_object_terms( $post->ID, $taxonomy, array("fields" => "ids") );
if ( ! empty($terms) ) {
echo '<form method="post" id="frontend_term_assignment_form">';
echo '<input type="hidden" value="' . wp_create_nonce('frontend_term_assignment') . '" name="term_assignment_nonce">';
echo '<input type="hidden" value="' . $post->ID . '" name="term_assignment_post_id">';
echo '<div class="' . $taxonomy . '_term_list"><ul>';
foreach ($terms as $term ) {
$checked = in_array($term->term_id, $post_terms) ? checked(1, 1, 0) : '';
printf('<li><label><input type="checkbox" value="%s" name="%s[]"%s> ' . $term->name . '</label></li>', $term->slug, $taxonomy, $checked);
}
echo '</ul><input type="submit" value="' . esc_attr( sprintf(__('Save %s'), $tax_obj->label) ) . '" />';
echo '</div></form>';
}
}
I’ve added security check like check the current user capabilities and a nonce check.
Almost all work are done.
Now in the templates (both single.php
and single-research.php
) just add the do_action after your loop:
<?php while ( have_posts() ) : the_post(); ?>
...Your loop code here ...
<?php endwhile; ?>
<?php
// Nothing else is required here!
do_action('frontend_term_assignment_form');
?>
That’s all. Hope it helps.