Frontend tagging for both default and custom post type in wordpress

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.

Leave a Comment