Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

Can somebody help me to create a drop-down menu or (radio buttons) in Wordpress comment form, so that a new user could make a selection of their user roles (for example teachers + students) ?

  1. Output from dropdown list or radio button would appear somewhere in the comments area.
  2. The best of all would also be if WordPress which already automatically populate
    email, login name would also display new extra field info (dropdown list OR
    radio button) to logged in users who already has their user roles assigned
  3. I don't want to use a plugin for that.
  4. I know that there a lot of tutorials about adding extra custom fields to the comment form including this web where I have found 3 similar requests unfortunately marked as duplicates, on my opinion they are not dups at all, because there's no code or tutorial for using known values as (select - dropdown- radio) button.
share|improve this question
    
Please pay attention to formatting. You posted all of that as a single sentence with very little appropriate punctuation. Even cleaned up, this is confusing and looks to be at least two different questions in one. Please edit the question for clarity. –  s_ha_dum Jun 2 '13 at 17:02
    
Ok, I will try my best, but English is not my native language, it is very hard for me to explain it better way –  Daniel Foltynek Jun 3 '13 at 0:51
add comment

1 Answer

up vote 5 down vote accepted
  • Filter comment_form_field_comment to add a select element with a label.
  • Add a callback to the action comment_post to save the value.
  • Filter comment_text to show the value for a comment.

Sample code:

add_filter( 'comment_form_field_comment', function( $field ) {

    global $wp_roles;

    $user = wp_get_current_user();

    $select = '<p><label for="roleselect">Your role:</label>
    <select name="prefix_role" id="roleselect">
    <option value="">Select a role</option>';

    foreach ( $wp_roles->roles as $key => $role )
        $select .= sprintf(
            '<option value="%1$s" %2$s>%3$s</option>',
            esc_attr( $key ),
            ( in_array( $key, $user->roles) ? 'selected' : '' ),
            esc_html( $role['name'] )
        );

    $select .= '</select></p>';

    return $select . $field;
});

add_action( 'comment_post', function( $comment_ID ) {

    $roles = new WP_Roles;
    $role_keys = array_keys( $roles->roles );

    if ( isset ( $_POST['prefix_role'] ) and in_array( $_POST['prefix_role'], $role_keys ) )
        update_comment_meta( $comment_ID, 'prefix_role', $_POST['prefix_role'] );
});

add_filter( 'comment_text', function( $text, $comment ) {

    if ( $role = get_comment_meta( $comment->comment_ID, 'prefix_role', TRUE ) )
        $text = "Role: $role<br> $text";

    return $text;
}, 10, 2 );

Update

I have rewritten the code to use a real MVC pattern. Explanation below. As plugin in GitHub.

Plugin header

<?php # -*- coding: utf-8 -*-
namespace WPSE;
/**
 * Plugin Name: Comment Meta Demo
 * Description: Create, save and display a comment meta field. Here, a commentator can select a role.
 * Plugin URI:  http://wordpress.stackexchange.com/q/101579/73
 * Version:     2013.06.06
 * Author:      Thomas Scholz
 * Author URI:  http://toscho.de
 * Licence:     MIT
 * License URI: http://opensource.org/licenses/MIT
 */

\add_action(
    'wp_loaded',
    array( __NAMESPACE__ . '\Comment_Meta_Controller', 'init' )
);

Controller

/**
 * Controller
 *
 * Assigns Views and models to actions and filters
 */
class Comment_Meta_Controller
{
    /**
     * Callback for add_action(). Creates a new instance.
     *
     * @wp-hook login_init
     */
    public function init()
    {
        return new self;
    }

    /**
     * Set up objects, register footer action callback.
     *
     * @wp-hook login_init
     */
    protected function __construct()
    {

        $data   = new Comment_Meta_Builtin_Roles( '_comment_role' );
        // Use this for custom roles instead
        //$data   = new Comment_Meta_Custom_Roles( '_comment_role' );
        $input  = new Comment_Meta_Role_Selector( $data );
        $output = new Comment_Meta_Role_Display( $data );

        // remove this if you want to show the select field with
        // do_action( 'comment_role_selector' );
        \add_filter( 'comment_form_field_comment', array ( $input, 'show' ), 10, 2 );

        \add_action( 'comment_role_selector', array ( $input, 'print_select' ) );

        // remove this if you want to show the select field with
        // do_action( 'comment_role_selector' );
        \add_filter( 'comment_text', array ( $output, 'show' ), 10, 2 );

        \add_action( 'comment_role_value', array ( $output, 'show_action' ), 10, 2 );

        if ( 'POST' === $_SERVER[ 'REQUEST_METHOD' ] )
            \add_action( 'comment_post', array ( $data, 'save' ) );
    }
}

Abstract meta data base class

/**
 * Base class for handling comment meta data.
 */
abstract class Comment_Meta_Data_Model
{
    /**
     * Meta key
     *
     * @type string
     */
    protected $key;

    /**
     * Constructor
     *
     * @param string $key
     */
    public function __construct( $key )
    {
        $this->key = $key;
    }

    /**
     * Get current key
     *
     * @return string
     */
    public function get_key()
    {
        return $this->key;
    }

    /**
     * Wrapper for the native get_comment_meta()
     *
     * @param  int    $comment_ID
     * @return string
     */
    public function get_comment_meta( $comment_ID )
    {
        $meta    = \get_comment_meta( $comment_ID, $this->key, TRUE );
        $allowed = $this->get_allowed_values();

        // get real display value
        if ( isset ( $allowed[ $meta ] ) )
            return $allowed[ $meta ];

        return '';
    }

    /**
     * Save comment mate data.
     *
     * @param  int  $comment_ID
     * @return bool
     */
    public function save( $comment_ID )
    {
        $role_keys = array_keys( $this->get_allowed_values() );

        if ( ! isset ( $_POST[ $this->key ] ) )
            return;

        if ( ! in_array( $_POST[ $this->key ], $role_keys ) )
            return;

        return \update_comment_meta( $comment_ID, $this->key, $_POST[ $this->key ] );
    }

    /**
     * Get user role.
     */
    public function get_current_value()
    {
        $user = \wp_get_current_user();

        if ( empty ( $user->roles ) )
            return array ();

        return $user->roles;
    }

    /**
     * @return array
     */
    abstract public function get_allowed_values();
}

Extended class for built-in roles

/**
 * User roles as comment meta.
 */
class Comment_Meta_Builtin_Roles extends Comment_Meta_Data_Model
{
    /**
     * (non-PHPdoc)
     * @see WPSE.Comment_Meta_Data_Model::get_allowed_values()
     */
    public function get_allowed_values()
    {
        global $wp_roles;

        if ( empty ( $wp_roles ) )
            $wp_roles = new \WP_Roles;

        $output = array();

        foreach ( $wp_roles->roles as $identifier => $role )
            $output[ $identifier ] = $role['name'];

        return $output;
    }
}

Extended class for custom selection of allowed roles

/**
 * Custom roles for comment meta.
 */
class Comment_Meta_Custom_Roles extends Comment_Meta_Data_Model
{
    /**
     * (non-PHPdoc)
     * @see WPSE.Comment_Meta_Data_Model::get_allowed_values()
     */
    public function get_allowed_values()
    {
        return array (
            'teacher' => 'Teacher',
            'student' => 'Student'
        );
    }
}

Basic comment meta view

/**
 * Base class to show comment meta data.
 */
class Comment_Meta_View
{
    /**
     * Model
     *
     * @type Comment_Meta_Data_Model
     */
    protected $data;

    /**
     * Constructor.
     *
     * @param Comment_Meta_Data_Model $data
     */
    public function __construct( Comment_Meta_Data_Model $data )
    {
        $this->data = $data;
    }
}

Use a select field as view

/**
 * Show role selector from comment meta
 */
class Comment_Meta_Role_Selector extends Comment_Meta_View
{
    /**
     * Add 'select' field before textarea.
     *
     * @param  string $text_field
     * @return string
     */
    public function show( $text_field )
    {
        return $this->get_select() . $text_field;
    }

    /**
     * Select element.
     *
     * @return string
     */
    public function get_select()
    {
        $allowed = $this->data->get_allowed_values();
        $current = $this->data->get_current_value();
        $key     = $this->data->get_key();

        // is the current value part of the allowed values?
        if ( ! empty ( $current ) && array() !== array_intersect( $allowed, $current ) )
            return $this->get_hidden_field( $key, $current[0] );

        $select = '<p>';
        $select .= sprintf( '<label for="%1$s_id">Your role:</label>
            <select name="%1$s" id="%1$s_id">',
            $key
        );
        $select .= '<option value="">Select a role</option>';

        foreach ( $allowed as $internal => $display )
            $select .= sprintf(
                '<option value="%1$s">%2$s</option>',
                \esc_attr( $internal ),
                \esc_html( $display )
            );

        return $select . '</select></p>';
    }

    /**
     * Print preselcted role as hidden input field.
     *
     * @param  string $name Field name
     * @param  string $role Internal role name
     * @return string
     */
    protected function get_hidden_field( $name, $role )
    {
        return sprintf(
            '<input type="hidden" name="%1$s" value="%2$s">',
            $name,
            esc_attr( $role )
        );
    }

    /**
     * Callback for do_action.
     *
     * @wp-hook comment_role_selector
     * @return  void
     */
    public function print_select()
    {
        print $this->get_select();
    }
}

Show the current role as view

/**
 * Show current comment role.
 */
class Comment_Meta_Role_Display extends Comment_Meta_View
{
    /**
     * Add role to comment text.
     *
     * @wp-hook comment_text
     * @param   string $text
     * @param   object $comment
     * @return  string
     */
    public function show( $text, $comment )
    {
        $role = $this->data->get_comment_meta( $comment->comment_ID );

        if ( '' !== $role )
            $text = "Role: $role<br> $text";

        return $text;
    }

    /**
     * Print the comment meta value into a template.
     *
     * Usage: <code>do_action( 'comment_role_value', 'Role: %s<br>', $comment );
     *
     * @wp-hook comment_role_value
     * @param   string $template
     * @param   object $comment
     * @return  void
     */
    public function show_action( $template, $comment )
    {
        $role = $this->data->get_comment_meta( $comment->comment_ID );

        if ( '' !== $role )
            printf( $template, $role );
    }
}

As you can see, we have seven classes now:

  1. Comment_Meta_Controller
    Here, the other classes are combined to do something useful.
  2. Comment_Meta_Data_Model Base class to handle the comment data. Cannot be used as is, must be extended.
  3. Comment_Meta_Builtin_Roles
    Extends Comment_Meta_Data_Model and uses all built-in roles. I have used this for my tests; you should probably use the next class. Change the Controller to do that.
  4. Comment_Meta_Custom_Roles
    Extends Comment_Meta_Data_Model. An alternative for Comment_Meta_Builtin_Roles.
    As you can see, you have to change just one method (function) to return an array of custom roles.
  5. Comment_Meta_View
    Base class for output. Cannot be used as is, must be extended.
  6. Comment_Meta_Role_Selector
    Extends Comment_Meta_View. Creates the select element. It doesn’t know anything about the source of your data and gets its values right from the View.
  7. Comment_Meta_Role_Display
    Extends Comment_Meta_View. Shows the current value for a comment.

Usage

To show the select field either …

  • Do nothing and let my defaults do the work. The select field will be set right above the comment text field then.
  • Or remove the line …

    \add_filter( 'comment_form_field_comment', array ( $input, 'show' ), 10, 2 );
    

    … and use in your comment form this code:

    do_action( 'comment_role_selector' );
    

To set custom values for the allowed roles, remove the line …

    $data   = new Comment_Meta_Builtin_Roles( '_comment_role' );

… and uncomment the following line. Then edit Comment_Meta_Custom_Roles.

To change the meta key, just change the value '_comment_role'. Make sure, you don’t use a built-in key from WordPress.

That’s all.

share|improve this answer
    
I have installed latest version from github as a plugin, I tried to activate it and got warning below: Parse error: syntax error, unexpected T_STRING in /home6/dancersr/public_html/4ella/wp-content/plugins/comment-meta-demo.php on line 2 I have removed whole line 2 and succesfully activated the plugin, after I have logged off from the website and went to see some post with comments, but there are only name, website, email and message fields, no select form, is it possible that it doesn't work because I use buddypress default theme and not wordpress? Deleted part is: namespace WPSE; –  Daniel Foltynek Jun 6 '13 at 17:00
    
@DanielFoltynek Your PHP version is very old, that’s why it doesn’t work. Upgrade immediately; you missed many important security fixes. And the code will work then too. :) –  toscho Jun 6 '13 at 17:24
1  
I got it and thank you for your advice :) , I have changed to 5.4 version, and your plugin works perfectly !! I have only one small issue, it shows me 15 other user roles, you can see it here: 4ella.com/2013/05/crazy-love-night-club-borgorose not only 2 roles I have written in your code, how can I show only those 2 roles which I want –  Daniel Foltynek Jun 6 '13 at 18:05
    
@DanielFoltynek Use the Comment_Meta_Custom_Roles instead of Comment_Meta_Builtin_Roles for $data in Comment_Meta_Controller::__construct(). –  toscho Jun 6 '13 at 18:08
    
Excellent, very nice work, works perfectly, I have one little suggestion for your future plugin improvement, mostly all the people on my site has already their 3 for me important user roles assigned, to logged in people who already has their role (again one of those 3 roles for me important) assigned I would like to hide the select field and I would like to print their roles automatically when they post a comment, is it doable? I wish I could have 15 reps to give you a vote for your hard work. –  Daniel Foltynek Jun 6 '13 at 18:35
show 14 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.