INTELLIGENT WORK FORUMS
FOR COMPUTER PROFESSIONALS

Log In

Come Join Us!

Are you a
Computer / IT professional?
Join Tek-Tips Forums!
  • Talk With Other Members
  • Be Notified Of Responses
    To Your Posts
  • Keyword Search
  • One-Click Access To Your
    Favorite Forums
  • Automated Signatures
    On Your Posts
  • Best Of All, It's Free!

*Tek-Tips's functionality depends on members receiving e-mail. By joining you are opting in to receive e-mail.

Posting Guidelines

Promoting, selling, recruiting, coursework and thesis posting is forbidden.

Jobs

Include additional field in comments for logged in users

Include additional field in comments for logged in users

Include additional field in comments for logged in users

(OP)
Hi all,

On my comments page(s) I have an additional field in my form called location. When a new user who is not logged in fills in a comment they may complete the non-required field 'location' and it displays this field ok.

However when the user is logged in the additional field is not part of the displayed fields, only the comments field is displayed. How, or where, do I include this additional field in my comments.php file so that it either displays in the form or is automatically recognised when the user is logged in and therefore displays their location against their comment?

Yours, confused...

 

RE: Include additional field in comments for logged in users

how are you creating the additional field? is this a plugin or a manual hack? if so, can you post the code?

RE: Include additional field in comments for logged in users

(OP)
Hi Justin,

It was created via the plug-in Extra Comments Field by Nate Weiner at www.ideashower.com and has created a new table in the database called wp_comments_extra.

When I backdated all my previous comments to the new database I had to manually interrogate the database for each entry in order to add their location because editing a comment in Wordpress loses the location field (it's obviously not built in to the standard edit page in Wordpress). I've noticed that Nate has not replied to any comments since July and this issue of losing extra fields in the edit page is a known issue, though this might not be relevant to my query.

The trick, then, is to let Wordpress know that when a user is logged in they are not only logged in a User X with email Y but also location Z.  

RE: Include additional field in comments for logged in users

Hi Jamie

sorry for delay.  i have had a brief look at the plugin code and although i hate speaking ill of fellow coders i think the code looks a bit amateurish.  

i might have a bash at fixing it or at writing a new plugin instead over the next while, but don't hold your breath!

as to your issue, it looks to me as though the extra fields are tied to the comment itself rather than to the user (which makes sense).  so a user could put in a different location for every comment that they post. thus there is no linkage that you can (validly) use between location and user.  

you _could_ write a query to grab the last used location for a user and pre-insert that. might be a bit much though.

however I cannot see why the location should be lost by editing the comment.  this should just update the comment but retain the same comment_id, so the query to retrieve the extra fields should not be prejudiced. unless, perhaps, WP deletes the comment and then re-adds it.  if it does this then the ecf_delete_comment function will be called and delete the extra info in the joined table.  i'll look into this and post back.

caveat: i've not studied the code in detail, nor have i plotted the functions at all.  so i may have got stuff totally wrong.

RE: Include additional field in comments for logged in users

(OP)
OK, Justin, keep us posted.

Re the plug-in: you may just win yourself some new fans out there with an improved plug-in, especially if it displays the additional field when logged in, as per my issue. I know I'm not the only one who has had this issue with editing code, so it could be a can of worms since no one has come back with a solution (at least to my knowledge).

Thanks for taking a look. Have a good evening.

Jamie

RE: Include additional field in comments for logged in users

hi Jamie

this is a bit clunky but try it for size.  migrating from your existing plugin is easy enough to do if you're happy with this.  note the two ways of displaying extra fields on the posted comments.  you may well prefer the manual method.

for the comments form you must include

CODE

<!--EXTRAFIELDS-->
where in the form you want the extra fields to go.  there is no granularity - they all go one after each other.  i would suggest adding them before the paragraph with the comments textarea in it.

you create the fields by completing the array at the top of the code.

there is a stubbed out method for creating a default value.  i was thinking of retrieving the last entered value for the relevant commenter as the current default.  easily done if that is what you are after.

note that no database changes are needed for this at all.  if performance becomes an issue it would probably be better to migrate to a separate database table, but let's wait and see.

hope that helps.

CODE --> plugin.php

<?php
/*
Plugin Name: Extra Fields in Comments
Plugin URI:
Description: Adds fields to your comments box
Version: 0.0.1
Author: Justin Adie
Author URI: http://rathercurious.net
*/
error_reporting(E_ALL ^E_NOTICE); ini_set('display_errors',true);
$extraCommentFields = new extraComments();
/**
 * wordpress plugin to enable the use of extra fields in WP comments.
 *
 * usage examples
 * method 1:    set $rewriteCommentText to true and everything is automated.
 * method 2:     manual method ...  retrieve the field value that you want, from your theme template,
 *                 with this template tag: $extraCommentFields->getValue('fieldname').
 *                 This RETURNS a value and does not echo it.  You must echo the value manually.
 */
class extraComments{
    /**
     * @var $fields array
     * a multi-dimensional array of extra field names and display types.  A class can also be added for styling purposes
     * currently only text boxes and textareas are supported.
     */
    private $fields = array    (
                        'location' =>    array(    
                                                'type'=>'text',
                                                'class'=>'',
                                                'label'=>'Location'
                                            ),
                            'notes' =>    array(    
                                                'type'=>'textarea',
                                                'class'=>'',
                                                'label'=>'notes:'
                                            ),
                    );
    
    /**
     * @var $salt
     * this variable is used to create a 'namespace' in the comments form
     */
    private $salt = "_xtraComment_";
    
    /**
     * @var
     * set this variable to true if you want the options to be auto-deleted when a comment is set to spam
     * note that this will fire with things like akismet too
     */
    private $deleteExtraIfSpam = true;
    /**
     * @var
     * set to true if you want the plugin to add the extra field data automatically to the comment text in displayed comments
     */
    private $rewriteCommentText = true;
    private $cache = array();
    
    public function __construct(){
        $this->addFilters();
    }
    
    /**
     * method that creates the necessary hooks in the plugin API
     * @return
     */
    public function addFilters(){
        add_action('delete_comment', array($this, 'deleteData'));
        add_action('comment_post', array($this, 'validateIncoming'),2);
        if ($this->rewriteCommentText){
            add_filter('comment_text', array($this, 'displayExtraFields'), 2000);
        }
        add_action('comment_form', array($this, 'addFieldToComment'));
    }
    private function getDefaultValue($name){
        return '';
    }
    /**
     * method for adding fields to the comments template
     * uses javascript to restructure the form order.  bit ugly...
     * @return
     */
    public function addFieldToComment(){
        $output = array();
        foreach ($this->fields as $name=>$field){
            $class = empty($field['class']) ? '' : 'class="'.$field['class'].'"';
            switch ($field['type']){
                case "text":
                    $output[] = <<<HTML
<p>
    <label for="{$this->salt}[{$name}]">{$field['label']}</label><br/>
    <input type="text" name="{$this->salt}[{$name}]" value="{$this->getDefaultValue($name)}" id="{$this->salt}_{$name}" $class />
</p>
HTML;
                break;
                case 'textarea':
                    $output[] = <<<HTML
<p>
    <label for="{$this->salt}[{$name}]">{$field['label']}</label><br/>
    <textarea name="{$this->salt}[{$name}]" id="{$this->salt}_{$name}" $class></textarea>
</p>
HTML;
                break;
                
            }
        }
        $_output = json_encode(implode(' ', $output));
        //yuk, here comes the horrible js....
        /*
         * methodology is to grab the form that we are in and work to the textarea (which will be the comment box). then add the $output as nodes after the comment box
         */
        $js = <<<JS
<script type="text/javascript">
/* <![CDATA[ */
function xtraFields_addNodes(){
    var html = $_output;
    var fm = document.getElementById('commentform');
    var contents = fm.innerHTML;
    fm.innerHTML = contents.replace(/<!--EXTRAFIELDS-->/, html);
}
var xtraFields = false;
xtraFields_addNodes();
/* ]]> */
</script>
JS;
    echo $js;
    }
    
    private function jsEscape($output){
        return js_escape($output);
    }
    /**
     * public method to return the value of a saved extra field.
     *
     * @return
     * @param object $fieldName
     */
    public function getValue($fieldName){
        global $comment;
        if (empty($this->cache[$comment->comment_ID])){
            $this->fillCache($comment->comment_ID);
        }
        if (isset($this->cache[$comment->comment_ID][$fieldName])){
            return $this->cache[$comment->comment_ID][$fieldName];
        } else {
            return '';
        }
    }
    
    /**
     * private method to create a cache for performance optimisation
     *
     * @return
     * @param object $commentID
     */
    private function fillCache($commentID){
        $this->cache[$commentID] = $this->retrieveData($commentID);
    }
    
    /**
     * method that takes the existing comment text and returns the comment text with the extra bits and bobs added
     * @return
     * @param object $commentText
     */
    public function displayExtraFields($commentText){
        global $comment;
        $output = '';
        //get the comment ID to retrieve the metaData
        $extraFields = $this->retrieveData ($comment->comment_ID);
        foreach ($extraFields as $field=>$value){
            //check to make sure whether a field is still wanted
            if ($this->wantedField($field)){
                //create different output templates depending on field type
                switch ($this->fields[$field]['type']){
                    case 'text':
                        $output .= <<<HTML
<div class="extraField">
    <span class="extraFieldLabel_text">{$this->fields[$field]['label']}</span>
    <span class="extraFieldData_text">{$value}</span>
</div>
HTML;
                    break;
                    case 'textarea':
                        $value = nl2br($value);
                        $output .= <<<HTML
<div class="extraField">
    <div class="extraFieldLabel_textarea">{$this->fields[$field]['label']}</div><div class="extraFieldData_textarea">{$value}</div>
</div>
HTML;
                    break;
                } //end switch
            } //end if
        } //end foreach
        return $commentText . $output;
    }
    
    private function wantedField($field){
        return array_key_exists($field, $this->fields);
    }
    
    /**
     * public method that runs when a comment is saved to the database
     *
     * method assembles the incoming values into an array to hand off to the update function
     * @return void
     * @param object $commentID
     * @param object $status
     */
    public function validateIncoming($commentID, $status=''){
        $values = array();
        if (!empty($_POST[$this->salt])){
            //we have some incoming data
            if (is_array($_POST[$this->salt])){
                foreach ($_POST[$this->salt] as $key=>$val){
                    
                    if ($this->wantedField($key)){
                        $values[$key] = $val;
                    }
                }
                $this->updateData($commentID, $values, $status);
            }
        }
    }
    
    /**
     * method that actually saves the extra data
     *
     * @return void
     * @param object $commentID
     * @param object $values
     * @param object $status
     */
    public function updateData($commentID, $values, $status){
    
        // if the comment is spam we automatically delete the data (if the option is set)
        if ($status === 'spam' && $this->deleteExtraIfSpam === true){
            $this->deleteData($commentID);
        } else {
            $optionID = 'extraComments_commentID_' . $commentID;
            $_values = serialize($values);
            $existingOptions = get_option ($optionID);
            if (!$existingOptions){
        
                add_option ($optionID, $_values, '', 'no');
            } else {
                if ($_values !== $existingOptions){
                    update_option ($optionID, $_values);
                }
            }
        }
    }
    
    /**
     * internal method to obtain the current data for a given comment
     *
     * @return array of extra field data.  If no data then empty array returned.
     * @param object $commentID
     */
    private function retrieveData($commentID){
        $array = array();
        $optionID = 'extraComments_commentID_' . $commentID;
        $existingOptions = get_option($optionID);
        
        if (!$existingOptions){
            return $array;
        } else {
            return unserialize($existingOptions);
        }
    }
    
    /**
     * method to delete extra fields associated with a comment
     * @return void
     * @param object $commentID
     */
    public function deleteData($commentID){
        $optionID = 'extraComments_commentID_' . $commentID;
        $existingOptions = get_option ($optionID);
        //test to see whether the option already exists.  If it does, then delete.
        if (!empty($existingOptions)){
            delete_option($optionID);
        }
    }
}
?>

RE: Include additional field in comments for logged in users

(OP)
OK, here's what I have so far after inserting the line <!--EXTRAFIELDS--> above my current location field:

http://www.followtheboat.com/index.php/contact/comment-page-3/#comment-141

You can see two extra comments. The first was submitted without logging in and echos the location and notes fields within the comments. However after submitting that and now becoming logged in, I submitted another comment but there is no echo of location or notes.

Admittedly I have not deactivated the original extra comment field plug-in. I'm worried that if I do I will lose the location for all the previous entries. Would having both on for the time being confuse wordpress?

Also how do I echo the location in the comment itself?

RE: Include additional field in comments for logged in users

can you send me the comments template you are using? or have I go that already?

Since the code works find on my machine using a variety of themes, this can only be because ... i dunno.  The display hook interrupts the comment-text itself to stop other things mucking about with it.  perhaps your theme is using a non-standard function?

I also assume that you are using the automated method for displaying meta-data? not the manual method?

RE: Include additional field in comments for logged in users

i have the template.

but i'm not understanding things, I think.  

Please
set up an extra field called FOO in my plugin and
add the <!--EXTRAFIELDS--> tag here in your template

CODE

<?php /* You might want to display this:  
        <p>XHTML: You can use these tags: <?php echo allowed_tags(); ?></p> */ ?>
        
        <!--EXTRAFIELDS-->
        
        
        <p><a class=screenshot rel=<?php bloginfo('template_directory'); ?>/images/tt-chat.gif>
                     <img src=<?php bloginfo('template_directory'); ?>/images/minichat.gif height=17 width=17></a> Your comments:<br>
        <textarea name="comment" id="comment" rows="5" cols="30"></textarea></p>
        


then respond (pls) to these questions:

1. in a non-logged-in state, do you see a new text box for foo in the comments form?  
2. in a logged-in state do you see a new text box for foo in the comments form?
3. in a logged in state do you see the VALUES for foo displayed in the posted comments?
4. in a non-logged-in state do you see the VALUES for foo displayed in the posted comments?

by the way, your url screenshot previewer appears to be broken.  that could well be stopping other js from executing properly.  i would recommend either fixing it or disabling it.
 

RE: Include additional field in comments for logged in users

(OP)
Hi

1. Yes
2. Yes
3. Yes, though currently they have not been styled to appear in the correct place
4. Yes

So, looks like all working ok. Now I need to know:

1. Where I style these new text boxes.
2. How I place the value of location in the correct place, i.e. outside the actual comment

I've noticed that since this morning I can't load my website correctly in IE. Is this what you are referring to with the URL screenshot previewer? What is a URL screenshot previewer???

RE: Include additional field in comments for logged in users

URL screenshot previewer looks to be a plugin you are running.  or maybe it is native in WP. i've not come across it before.  it's manifesting as a bit of jQuery javascript that is not working.  i think it breaks because you don't have an element called screenshot somewhere but i've not given it much attention.

don't use IE (i'm on a mac) so can't comment!

the text boxes for the form can be styled by adding a value for class to the array and adding an appropriate css declaration.

the text of the fields (as in display rather than edit) can be styled through using the classes
.extraField  - for the wrapper around each label-value pair
.extraFieldLabel_text - for the label for a text field
.extraFieldLabel_textarea
.extraFieldData_text
.extraFieldData_textarea

or you can abandon these styles and go for the non-automated method, edit the them directly and apply markup as you will.  just echo out the field value with

CODE

echo $extraCommentFields->getValue('fieldname');

RE: Include additional field in comments for logged in users

(OP)
Aha, I think this is a gallery light-box issue, with a call to some js files in my header. Need to contact the author to work out why not working in IE. Thanks for pointing it out...

RE: Include additional field in comments for logged in users

Is the rest working as expected now?

RE: Include additional field in comments for logged in users

(OP)
Hi Justin,

Only just got back to this thread as we have lost our cat (always a worry when you live on a boat)!

I will take a look at this first thing tomorrow a.m. Also I need to work out what this js error is, though it seems I'm not the only one with the problem (http://www.huddletogether.com/forum/). I don't use IE either so I may have just wasted a day with this code as I only spotted it shortly before you mentioned it. Grrr.

I'll give you an update on the comments form tomorrow. Looks straightforward.

Have a good evening and thank you for your time.

 

RE: Include additional field in comments for logged in users

couple more things before I clean this up and publish it:

1. do you want the 'default' concept implemented?
2. is everything working the way you think it should, or would you like to see any enhancements/changes?

 

RE: Include additional field in comments for logged in users

sorry to hear about your cat.  we only have outdoor cats that have adopted us rather than vice versa.  round us the concerns are more to do with hunters mistaking them for hares in the vines (we live in the wine country in the south of france).  Touch wood, none of the moggies that have adopted us have met untimely ends - we don't 'tend' to them, though (food and water very rarely, but attention rather a lot), so they grow up a curious mix of ferile, self-dependent and cuddly.  

before our first realised it was an outdoor cat it once climbed up the cherry tree, jumped on to our verandah roof, wandered around the house and climbed in my bedroom window; shortly afterwards landing on my bed and peering into my rather startled eyes.  I was on my own that night.  I'm also really badly allergic to cats ...  i had a big 'crise de conscience' as to how i was going to get the cat outside again without either hurting it or touching it.  succeeded in the end, but the cat thought it a great game and continued its journeys to my bedroom leaving me to sleep with windows closed and suffer the stultifying heat...

 

RE: Include additional field in comments for logged in users

(OP)
Good morning Justin.

Cat turned up last night at 9pm. Needless to say she was gently reprimanded and sent to her bedroom without supper. We think she got stuck somewhere because her stomach normally has her on the boat squeaking for food by 5pm ;)

OK, I've just had my morning coffee and ready for another day. With regards to the comments section the implementation of that additional field 'location' was all I was after (it's important to me since our website is a travelogue). I can't see anything else being required. Should I want to add avatars and things that's all straightforward, it was just this one field.

When you say 'default concept' implemented do you mean to have all fields published?

Ultimately this should happen:

1. All fields styled as per my current form (brown background)
2. When not logged in, forced to give a location, as well as the usual other fields
3. When logged in the location is remembered
4. Published comments shows:
 Line 1: Name and location. Name should be a link if they supplied a URL
 Line 2: Date
 Then alternating styled comment (unless it's author ID=1, in which case it's the third style)
4b. All points in 4. are as per my current comments style. The only difference is the addition of a link if they supplied a URL
5. The actual name of the field does not need to be echoed

So to recap: it's exactly as per my current comments style, with alternating styled comments, with just the addition of the 'location' field, which is required in order to submit comment. The URL is not required but if submitted it makes the name a link.

I'm online all day so any question just let me know.

Thank you.

RE: Include additional field in comments for logged in users

default concept: the concept of how to derive a default value as per my post of 8 Jan 09 @ 19h00

Quote:


 i was thinking of retrieving the last entered value for the relevant commenter as the current default.

1. styling of the input boxes: that is totally user configurable in the style sheet and by supplying a class to the array. or for field specific styling you can use the id that is generated ({$this->salt}_{$name}")
2. mandatory field: more difficult.  there is no hook that allows us to fail a comment submission. will think upon.
3. logged-in = remembered field (i need to be field agnostic here, but appreciate that you are looking only at location). See above for my best answer.  a default can also be added in the array.
4. styling of published comments: entirely user drivable.  For example in your case you could use this in your theme

CODE

<div class="comment-author">From <?php comment_author(); echo empty($extraCommentFields->getValue('location')) ? ", in $extraCommentFields->getValue('location')" : '';?></div>
<div class="comment-date"><?php comment_date() ?></div>
and switch  

CODE

$rewriteCommentText = false;
then all you get back is text and you can style with added mark-up exactly how you want.
5. comment author's name to be displayed as a link if url provided.  nothing to do with an extra fields plugin!  Just change

CODE

<?php comment_author();?>
to

CODE

<?php comment_author_link(); ?>
5. it will be echoed if you use the automatic method (toggled with $rewriteCommentText).  If you use the manual method (toggle set to false) then the output of all data for published fields is up to you.

 

RE: Include additional field in comments for logged in users

(OP)
OK, almost done except most important bit!

If I cut and paste this code

CODE

<div class="comment-author">From <?php comment_author(); echo empty($extraCommentFields->getValue('location')) ? ", in $extraCommentFields->getValue('location')" : '';?></div>
<div class="comment-date"><?php comment_date() ?></div>
it returns an error on line 99 of comments.

I need a bit of hand-holding here. My actual code currently is this:

CODE

<li id="comment-<?php comment_ID(); ?>" class="<?php echo $commentClass;?>">
            <?php comment_author_link() ?>, <?php print $comment->extra_location; ?>
            <br><div class="comment-date"><?php comment_date() ?></div>

What is the exact code for location echo that I need in order to replace this bit:

CODE

<?php print $comment->extra_location; ?>
 

RE: Include additional field in comments for logged in users

CODE

<li id="comment-<?php comment_ID(); ?>" class="<?php echo $commentClass;?>">
  <?php comment_author_link();
  echo empty($extraCommentFields->getValue('location')) ? ", in {$extraCommentFields->getValue('location')}" : ''; ?>
  <div class="comment-date">
    <?php comment_date() ?>
  </div>

not sure what line 99 is to be able to resolve that one.
 

RE: Include additional field in comments for logged in users

(OP)
Now error is line 100:

Quote:

Fatal error: Can't use method return value in write context in E:\domains\f\followtheboat.com\user\htdocs\wp-content\themes\followtheboat\comments.php on line 100

Line 100 is:

CODE

echo empty($extraCommentFields->getValue('location')) ? ", in {$extraCommentFields->getValue('location')}" : ''; ?>

Is there a ' or bracket missing or something?

RE: Include additional field in comments for logged in users

(OP)
BTW - if you go to the page you won't see the error as I've placed the old code back in (I'm working on another page with this code and need it to function).

RE: Include additional field in comments for logged in users

sorry for the delay.

the problem was sloppy coding by me.  solution:

1. in your comments.php file add this as the first line

CODE

<?php global $extraCommentFields; ?>

and then in the comment loop

CODE

<li id="comment-<?php comment_ID(); ?>" class="<?php echo $commentClass;?>">
  <?php comment_author_link();
  echo ($extraCommentFields->getValue('location'))
        ? ", in {$extraCommentFields->getValue('location')}"
        : '';?>
  <div class="comment-date">
    <?php comment_date() ?>
  </div>
  <?php comment_author_link();

i will post a version that uses a database table and has the default value retrieval sometime tomorrow or Monday.

RE: Include additional field in comments for logged in users

(OP)
Hey, no rush, Justin. I'm almost there, I just need to know where in the code it is echoing the label of the location. As you can see in the most recent comment (no. 113) it is echoing the label 'Your location (town and country)' within the comment itself. I need to switch this off. I presume this is set in the plug-in file somewhere?  

RE: Include additional field in comments for logged in users

yes.  This is an option within the plugin.  Just toggle $rewriteCommentText to FALSE.

attached is a revised version.  key differences are:

1. it uses a database to store the field values on a per comment basis. this makes it significantly easier/faster to retrieve default values.
2. there is a user interface for creating and deleting fields. find this under settings in the admin section.

all else remains largely as was.  the automated method (toggle $rewriteCommentText to true) will embed the label->value pairs in the comment text itself.  turn this off to use the manual method getValue().

The user interface does not provide an edit mechanism.  just delete a field and recreate it with the same fieldname.  No data is destroyed whilst deleting a fieldname.

Note that if you specify a comment as spam, the extra fields will be deleted for that comment and will not be retrievable even if you subsequently redesignate the comment as not-spam.  If you do not want this behaviour, toggle $deleteExtraIfSpam to FALSE.  

I have tested this code but if you do find faults, please post back.

CODE

<?php
/*
Plugin Name: Extra Fields in Comments
Plugin URI:
Description: Adds fields to your comments box
Version: 0.0.1
Author: Justin Adie
Author URI: http://rathercurious.net
*/
error_reporting(E_ALL ^E_NOTICE); ini_set('display_errors',true);

/**
 * wordpress plugin to enable the use of extra fields in WP comments.
 *
 * usage examples
 * method 1:    set $rewriteCommentText to true and everything is automated.
 * method 2:     manual method ...  retrieve the field value that you want, from your theme template,
 *                 with this template tag: $extraCommentFields->getValue('fieldname').
 *                 This RETURNS a value and does not echo it.  You must echo the value manually.
 */
if (!class_exists('extraComments')):
class extraComments{
    /**
     * @var $fields array
     * a multi-dimensional array of extra field names and display types.  A class can also be added for styling purposes
     * currently only text boxes and textareas are supported.
     */
    private $fields = array();
    
    /**
     * @var $salt
     * this variable is used to create a 'namespace' in the comments form
     */
    private $salt = "_xtraCommentFields_";
    
    /**
     * @var
     * set this variable to true if you want the options to be auto-deleted when a comment is set to spam
     * note that this will fire with things like akismet too
     */
    private $deleteExtraIfSpam = true;
    
    /**
     * @var
     * set to true if you want the plugin to add the extra field data automatically to the comment text in displayed comments
     */
    private $rewriteCommentText = true;
    public $cache = array();
    private $table = '';
    
    /**
     * constructor method to initialise variables and add the filters used by wp hooks
     * @return
     */
    public function __construct(){
        global $wpdb;
        $this->table = $wpdb->prefix . 'extraFieldsinComments';
        $this->fields = get_option('extraFieldsinComments');
        if (!$this->fields){
            $this->fields = array();
        } else {
            $this->fields = unserialize($this->fields);
        }
        $this->addFilters();
    }
    
    /**
     * method that creates the necessary hooks in the plugin API
     * @return
     */
    public function addFilters(){
        add_action('admin_menu', array($this, 'addManagementPage'));
        add_action('delete_comment', array($this, 'deleteData'));
        add_action('comment_post', array($this, 'validateIncoming'),2);
        if ($this->rewriteCommentText){
            add_filter('comment_text', array($this, 'displayExtraFields'), 2000);
        }
        add_action('comment_form', array($this, 'addFieldToComment'));
    }
    
    /**
     * helper method for adding the settings page to create fields etc
     * @return
     */
    public function addManagementPage(){
        add_options_page('Extra Fields for Comments', 'Extra Fields for Comments', 10, __FILE__, array($this, "showOptionsPage"));
    }
    
        /**
     * method used to create the options page and to process the results of form submissions
     *
     * @return
     */
    public function showOptionsPage(){
        $formUrl = str_replace( '%7E', '~', $_SERVER['REQUEST_URI']);
        $hfn = "extraFieldsOption";
        $update = '';
        //zero form fields to defaults
        $array = array (
                    'fieldName'=>'',
                    'label'=>'',
                    'class'=>'',
                    'other'=>'',
                    'defaultValue'=> array(    'lastSubmitted'=>'checked="checked"',
                                            'other'=>'',
                                            'none'=>''),
                    'fieldType'=> array (    'text'=>'checked="checked"',
                                            'textarea'=>'')
                        );
        
        //create the javascript for delete effects
        //todo...
        
        if (isset($_POST['Submit'])){
            
                if ($_POST['action'] == 'deleteField'){
                    echo 'deleting';
                    if (isset($_POST['fieldName'])){
                        unset($this->fields[$_POST['fieldName']]);
                        update_option('extraFieldsinComments', serialize($this->fields));
                        $update = "Field $fieldName deleted";
                    } else {
                        $update = "Error: no field name provided for deletion";
                    }
                } elseif (isset($_POST[$hfn]) && $_POST[$hfn] == "Y"){
                    if (check_admin_referer('add_new_extra_field')){
                        //process the new field
                        //validate fields
                        if (empty($_POST['fieldName'])){
                            $update = "Error: No field name provided";
                        } elseif (isset($this->fields[$_POST['fieldName']])){
                            $update = "Error: The field name $_POST[fieldName] is already in use.";
                        } elseif (empty($_POST['label'])){
                            $update = "Error: No label provided";
                        } elseif ($_POST['defaultValue'] === 'other' && empty($_POST['defaultValue'])){
                            $update = " Error: You have specified a default value but not provided one";
                        } else {
                            if ($_POST['defaultValue'] ==='other'){
                                $default = $_POST['other'];
                            } else{
                                $default = $_POST['defaultValue'];
                            }
                            $this->fields[$_POST['fieldName']] = array('label'=>$_POST['label'],
                                                                        'type'=>$_POST['fieldType'],
                                                                        'default'=>$default,
                                                                        'class'=>$class);
                            update_option('extraFieldsinComments', serialize($this->fields));
                            $update = "New field $_POST[fieldName] added";
                        }
                    } else {
                        //back button resubmission
                        $update = "You have already done that!";
                    }//admin referer
                }
            
        }
        
        //get current fields
        $tbody = '';
        
        
        foreach ($this->fields as $name=>$field){
                $tbody .= <<<TB
    <tr>
        <td>{$name}</td>
        <td>{$field['label']}</td>
        <td>{$field['type']}</td>
        <td>{$field['default']}</td>
        <td>{$field['class']}</td>
        <td><form name="form1" method="post" action="{$formUrl}"><input type="hidden" value="$name" name="fieldName" /> <input type="hidden" value="deleteField" name="action"/><input type="submit" value="Delete" name="Submit"/> </form></td>
    </tr>
TB;
        }
        
        
        if (substr($update, 0, 5) == "Error"){
            $newArray = array_merge($array, $_POST);
            print_r($newArray);
            extract($newArray);
        } else {
            extract ($array);
        }
        echo <<<HTML
<div class="wrap">
    <h2>Extra Fields for Comments</h2>
    <h3>Add a field</h3>
    {$update}
    <form name="form1" method="post" action="{$formUrl}">
            <p>
            <label for="fieldName">Name:</label><br/>
            <input type="text" name="fieldName" id="fieldName" value="{$fieldName}" />
            </p>
            <p>
            <label for="class">Label</label> <br/>
            <input type="text" name="label" id="class" value="$label" />
            </p>
            <p>
            <label for "fieldType">Field Type</label><br/>
            <input type="radio" name="fieldType" value="text" {$this->getChecked('fieldType', 'text')}/>&nbsp;Text<br/>
            <input type="radio" name="fieldType" value="textarea" {$this->getChecked('fieldType', 'textarea')} />&nbsp;Textarea
            </p>
            <p>
            <label for="class">Class</label> <br/>
            <input type="text" name="class" id="class" value="$class" />
            </p>
            <p>
            <label for="defaultValue">Default Value</label><br/>
            <input type="radio" name="defaultValue" value="last submitted" {$this->getChecked('defaultValue', 'last submitted')} />&nbsp;Last Submitted Value for the Comment Author<br/>
            <input type="radio" name="defaultValue" value="other" {$this->getChecked('defaultValue', 'other')} />&nbsp;Other <input type="text" name="other" value="$other" /><br/>
            <input type="radio" name="defaultValue" value="none" {$this->getChecked('defaultValue', 'none')}/>&nbsp;None
            <hr />
    
            <p class="submit">
            <input type="submit" name="Submit" value="Create Field" />
            <input type="hidden" name="{$hfn}" value="Y" />
HTML
. wp_nonce_field('add_new_extra_field') . <<<HTML

            </p>
    </form>
    <hr/>
    <h3>Current Fields</h3>
        <p>
        <table class="widefat">
            <thead>
            <tr>
                <th scope="col">Field Name</th>
                <th scope="col">Label</th>
                <th scope="col">Type</th>
                <th scope="col">Default</th>
                <th scope="col">Class</th>
                <th scope="col">&nbsp;</th>
            </tr>
            </thead>
            <tbody>
                {$tbody}
            </tbody>
        </table>
        </p>
</div>
HTML;
    }
    

    
    /**
     * method for adding form fields to the comments template
     * uses javascript to restructure the form order.  bit ugly...
     * @return
     */
    public function addFieldToComment(){
        $output = array();
        foreach ($this->fields as $name=>$field){
            $class = empty($field['class']) ? '' : 'class="'.$field['class'].'"';
            switch ($field['type']){
                case "text":
                    $output[] = <<<HTML
<p>
    <label for="{$this->salt}[{$name}]">{$field['label']}</label><br/>
    <input type="text" name="{$this->salt}[{$name}]" value="{$this->getDefaultValue($name)}" id="{$this->salt}_{$name}" $class />
</p>
HTML;
                break;
                case 'textarea':
                    $output[] = <<<HTML
<p>
    <label for="{$this->salt}[{$name}]">{$field['label']}</label><br/>
    <textarea name="{$this->salt}[{$name}]" id="{$this->salt}_{$name}" $class></textarea>
</p>
HTML;
                break;
                
            }
        }
        $_output = json_encode(implode(' ', $output));
        //yuk, here comes the horrible js....
        /*
         * methodology is to grab the form that we are in and work to the textarea (which will be the comment box). then add the $output as nodes after the comment box
         */
        $js = <<<JS
<script type="text/javascript">
/* <![CDATA[ */
function xtraFields_addNodes(){
    var html = $_output;
    var fm = document.getElementById('commentform');
    var contents = fm.innerHTML;
    fm.innerHTML = contents.replace(/<!--EXTRAFIELDS-->/, html);
}
var xtraFields = false;
xtraFields_addNodes();
/* ]]> */
</script>
JS;
    echo $js;
    }
    
    
    /**
     * public method to return the value of a saved extra field.
     *
     * @return
     * @param object $fieldName
     */
    public function getValue($fieldName){
        global $comment;
        if (empty($this->cache[$comment->comment_ID])){
            $this->fillCache($comment->comment_ID);
        }
        if (isset($this->cache[$comment->comment_ID][$fieldName])){
            return $this->cache[$comment->comment_ID][$fieldName];
        } else {
            return '';
        }
    }
    
    /**
     * method that takes the existing comment text and returns the comment text with the extra bits and bobs added
     * @return
     * @param object $commentText
     */
    public function displayExtraFields($commentText){
        
        //do not add extra data if we are in the admin edit menu
        if (is_admin){
            return $commentText;
        }
        global $comment;
        $output = '';
        //get the comment ID to retrieve the metaData
        $extraFields = $this->retrieveData ($comment->comment_ID);
        foreach ($extraFields as $field=>$value){
            //check to make sure whether a field is still wanted
            if ($this->wantedField($field)){
                //create different output templates depending on field type
                switch ($this->fields[$field]['type']){
                    case 'text':
                        $output .= <<<HTML
<div class="extraField">
    <span class="extraFieldLabel_text">{$this->fields[$field]['label']}</span>
    <span class="extraFieldData_text">{$value}</span>
</div>
HTML;
                    break;
                    case 'textarea':
                        $value = nl2br($value);
                        $output .= <<<HTML
<div class="extraField">
    <div class="extraFieldLabel_textarea">{$this->fields[$field]['label']}</div><div class="extraFieldData_textarea">{$value}</div>
</div>
HTML;
                    break;
                } //end switch
            } //end if
        } //end foreach
        return $commentText . $output;
    }
    
    /**
     * public method that runs when a comment is saved to the database
     *
     * method assembles the incoming values into an array to hand off to the update function
     * @return void
     * @param object $commentID
     * @param object $status
     */
    public function validateIncoming($commentID, $status=''){
        $values = array();
        if (!empty($_POST[$this->salt])){
            //we have some incoming data
            if (is_array($_POST[$this->salt])){
                foreach ($_POST[$this->salt] as $key=>$val){
                    
                    if ($this->wantedField($key)){
                        $values[$key] = $val;
                    }
                }
                $this->updateData($commentID, $values, $status);
            }
        }
    }
    
    /**
     * method that actually saves the extra data
     *
     * @return void
     * @param object $commentID
     * @param object $values
     * @param object $status
     */
    public function updateData($commentID, $values, $status){
        global $wpdb;
        // if the comment is spam we automatically delete the data (if the option is set)
        if ($status === 'spam' && $this->deleteExtraIfSpam === true){
            $this->deleteData($commentID);
        } else {
            $this->deleteData($commentID);
            $sql = "Insert into $this->table (comment_ID, extraFields) values (%d, %s)";
            $prepare = $wpdb->prepare($sql, $commentID, serialize($values));
        //    echo "prepared sql is $prepare";
            $wpdb->query($prepare);
        }
    }
    
    /**
     * internal method to obtain the current data for a given comment
     *
     * @return array of extra field data.  If no data then empty array returned.
     * @param object $commentID
     */
    public function retrieveData($commentID){
        global $wpdb;
        $array = array();
        $existingOptions = $wpdb->get_var($wpdb->prepare("Select extraFields from {$this->table} where comment_ID=%d", $commentID));
        
        if (!$existingOptions){
            return $array;
        } else {
            return unserialize($existingOptions);
        }
    }
    
    /**
     * method to delete extra fields associated with a comment
     * @return void
     * @param object $commentID
     */
    public function deleteData($commentID){
        global $wpdb;
        $wpdb->query($wpdb->prepare("delete from {$this->table} where comment_ID=%d"));
    }
    
    
    /**
     * method to install the necessary database fields and tables for the plugin
     *
     * @return
     */
    public function init(){
        global $wpdb;
        
        if( 0 != strcasecmp ($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $this->table)), $this->table)) {
            
            $sql = "CREATE TABLE {$this->table} (
                    comment_ID  bigint(20) NOT NULL,
                    extraFields longtext,
                    UNIQUE KEY comment_ID (comment_ID)
                    );";
            require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
            dbDelta($sql);
        }
    }
    
    /**
     * method to auto-fill the fields with a user specified default value or a computed value based on a last known entry
     * @return string
     * @param object $fieldName
     */
    private function getDefaultValue($fieldName){
    //    return $this->fields[$fieldName]['default'];
        switch ($this->fields[$fieldName]['default']){
            case 'last submitted':
                global $user_email, $wpdb;
                if (empty($user_email)){
                    return '';
                }
                $_fieldName = $wpdb->escape($fieldName);
                $sql = "select extraFields from {$this->table} ef join {$wpdb->prefix}comments o on (o.comment_ID = ef.comment_ID) where ef.extraFields like '%%$_fieldName%%' and comment_author_email = %s order by o.comment_date_gmt desc LIMIT 1";
                $sql = $wpdb->prepare($sql, $user_email);
                $result = $wpdb->get_var($sql);
                if (empty($result)){
                    return '';
                }
                $result = unserialize($result);
                if (is_array($result) && isset($result[$fieldName])){
                    return $result[$fieldName];
                } else {
                    return '';
                }
                
            break;
            case 'none':
                return '';
            break;
            default:
                return $this->fields[$fieldName]['default'];
        }
    }
    
    /**
     * method used to make radio and checkboxes sticky
     * @return
     * @param object $field
     * @param object $value
     */
    private function getChecked($field, $value){
        if (empty($_POST[$field])){
            return '';
        } else {
            if ($_POST[$field] == $value){
                return 'checked="checked"';
            } else {
                return '';
            }
        }
    }
    
    /**
     * private method to create a cache for performance optimisation
     *
     * @return
     * @param object $commentID
     */
    private function fillCache($commentID){
        $this->cache[$commentID] = $this->retrieveData($commentID);
    }
    
    /**
     * method to discard stored fields that are no longer required for display
     *
     * @return
     * @param object $field
     */
    private function wantedField($field){
        return array_key_exists($field, $this->fields);
    }
}
endif;
$extraCommentFields = new extraComments();
register_activation_hook(__FILE__, array(&$extraCommentFields, 'init'));

?>

RE: Include additional field in comments for logged in users

btw, i also have a version that will migrate your old extra fields to the new scheme (non-destructively).

and i should have also added that to make the plugin above work you will need to deactivate it and then reactivate it.  this will create the db schema.

RE: Include additional field in comments for logged in users

(OP)
Blimey. I've just tested this and it appears to work a treat! This could go down a storm at wordpress.org, Justin.

I have a couple of things to comment on.

1. How is the class added? I tried adding '#location' as this is the class in my stylesheet, but no joy. So I then added 'background-color:#c0c0c0' but that doesn't work either.

2. Could do with an 'edit' column once the field has been created. I made a mistake on my first creation, which was location without a class, so I had to delete my first one and add a new one.

3. When I did this I named this 'location' again and there was still no class attribute (background-color:#c0c0c0). Does deleting and creating a new field and calling it the same confuse the database?

4. I haven't done it yet but I assume I just add in my new field in my comments.php template in order to display the new field? At the moment my comments.php template still has the

CODE

  <?php comment_author_link();
  echo ($extraCommentFields->getValue('location'))
        ? ", {$extraCommentFields->getValue('location')}"
        : '';?>
left over from last time and this is displaying everything correctly.

Good work, Justin. Excellent stuff. I can see real mileage in this - there's no reason why users can't add media and more complex html in comments with this plug-in.

RE: Include additional field in comments for logged in users

1. #location is not a class based declaration.  try .location instead.

2. editing is a bit of a pain.  might chalk it up for version 2....

3. nope, not at all.  not intelligent enough to be confused!  probably the issue is that you were using an id css declaration rather than a class.

4. that exact code will still work just fine.  assuming your extra field is called 'location' (remember it is case sensitive.

let me know if you want the migration code too.
 

RE: Include additional field in comments for logged in users

(OP)
If you have already written the migration code then I'd definitely find it useful as you can see all my previous comments currently don't have their location displayed. Otherwise don't sweat over it.

Do you have plans to make this code public? I really think people would find it useful (though you could get lost in the support of such a thing).

Top marks for this one, Justin. Really appreciate your time and efforts. Thank you.

RE: Include additional field in comments for logged in users

(OP)
Three further comments:

1. It doesn't appear to be saving the class value, unless I'm inputting it incorrectly? I'm assuming I just put in '.location' and it will pick this up from the style sheet. Is this correct or am I creating the style from scratch and inputting it as if I were adding it to an HTML document? Could you give me an example if the latter?

2. It's not a big deal but I forgot to declare the text type and it saved my field without this value. Perhaps for the next version it should not save the new field unless all values have been completed.

3. Possible future development: I've just implemented a new comments page with different styling (comments2.php). One would be comments as we see it currently but the other one is for people's blogs, therefore requiring different fields. Possible in next version to be able to switch on and off the extra fields depending upon which comments template is used? Perhaps a work-around could be to manually insert the fields instead of the <!--EXTRAFIELDS--> line, giving greater control over the placement of the fields. Just a thought.

RE: Include additional field in comments for logged in users

In the class field type just location. Then to set up the css rules for this class add a style as follows:
.location{background-color:brown;}
In your stylesheet.

The form stickiness and default values are fixed in the next release and conditionalising the plugin can be done without changing it(in the theme) unless I have misunderstood.  

RE: Include additional field in comments for logged in users

(OP)
I'm pretty sure it's not saving the class. I've tried entering .location, location and #location, whilst the style.css is

CODE

.location {background-color: #c19c3c;}
. After saving my field the plug-in page shows my field attributes but the class column is blank.

RE: Include additional field in comments for logged in users

my fault. coding error again... revised code below.

i have not fully updated the code to handle the sticky form fields etc. nor have i implemented an edit function yet.

CODE

<?php
/*
Plugin Name: Extra Fields in Comments
Plugin URI:
Description: Adds fields to your comments box
Version: 0.2.0
Author: Justin Adie
Author URI: http://rathercurious.net
*/
error_reporting(E_ALL ^E_NOTICE); ini_set('display_errors',true);

/**
 * wordpress plugin to enable the use of extra fields in WP comments.
 *
 * usage examples
 * method 1:    set $rewriteCommentText to true and everything is automated.
 * method 2:     manual method ...  retrieve the field value that you want, from your theme template,
 *                 with this template tag: $extraCommentFields->getValue('fieldname').
 *                 This RETURNS a value and does not echo it.  You must echo the value manually.
 */
if (!class_exists('extraComments')):
class extraComments{
    /**
     * @var $fields array
     * a multi-dimensional array of extra field names and display types.  A class can also be added for styling purposes
     * currently only text boxes and textareas are supported.
     */
    private $fields = array();
    
    /**
     * @var $salt
     * this variable is used to create a 'namespace' in the comments form
     */
    private $salt = "_xtraCommentFields_";
    
    /**
     * @var
     * set this variable to true if you want the options to be auto-deleted when a comment is set to spam
     * note that this will fire with things like akismet too
     */
    private $deleteExtraIfSpam = true;
    
    /**
     * @var
     * set to true if you want the plugin to add the extra field data automatically to the comment text in displayed comments
     */
    private $rewriteCommentText = true;
    public $cache = array();
    private $table = '';
    
    /**
     * constructor method to initialise variables and add the filters used by wp hooks
     * @return
     */
    public function __construct(){
        global $wpdb;
        $this->table = $wpdb->prefix . 'extraFieldsinComments';
        $this->fields = get_option('extraFieldsinComments');
        if (!$this->fields){
            $this->fields = array();
        } else {
            $this->fields = unserialize($this->fields);
        }
        $this->addFilters();
    }
    
    /**
     * method that creates the necessary hooks in the plugin API
     * @return
     */
    public function addFilters(){
        add_action('admin_menu', array($this, 'addManagementPage'));
        add_action('delete_comment', array($this, 'deleteData'));
        add_action('comment_post', array($this, 'validateIncoming'),2);
        if ($this->rewriteCommentText){
            add_filter('comment_text', array($this, 'displayExtraFields'), 2000);
        }
        add_action('comment_form', array($this, 'addFieldToComment'));
    }
    
    /**
     * helper method for adding the settings page to create fields etc
     * @return
     */
    public function addManagementPage(){
        add_options_page('Extra Fields for Comments', 'Extra Fields for Comments', 10, __FILE__, array($this, "showOptionsPage"));
    }
    
        /**
     * method used to create the options page and to process the results of form submissions
     *
     * @return
     */
    public function showOptionsPage(){
        $formUrl = str_replace( '%7E', '~', $_SERVER['REQUEST_URI']);
        $hfn = "extraFieldsOption";
        $update = '';
        //zero form fields to defaults
        $array = array (
                    'fieldName'=>'',
                    'label'=>'',
                    'class'=>'',
                    'other'=>'',
                    'defaultValue'=> array(    'lastSubmitted'=>'checked="checked"',
                                            'other'=>'',
                                            'none'=>''),
                    'fieldType'=> array (    'text'=>'checked="checked"',
                                            'textarea'=>'')
                        );
        
        //create the javascript for delete effects
        //todo...
        
        if (isset($_POST['Submit'])){
            
                if ($_POST['action'] == 'deleteField'){
                    if (isset($_POST['fieldName'])){
                        unset($this->fields[$_POST['fieldName']]);
                        update_option('extraFieldsinComments', serialize($this->fields));
                        $update = "Field $fieldName deleted";
                    } else {
                        $update = "Error: no field name provided for deletion";
                    }
                } elseif ($_POST['action'] == 'migrate'){
                    if ($this->migrate){
                        $update = 'Migration complete';
                    }
                }elseif (isset($_POST[$hfn]) && $_POST[$hfn] == "Y"){
                    if (check_admin_referer('add_new_extra_field')){
                        //process the new field
                        //validate fields
                        if (empty($_POST['fieldName'])){
                            $update = "Error: No field name provided";
                        } elseif (isset($this->fields[$_POST['fieldName']])){
                            $update = "Error: The field name $_POST[fieldName] is already in use.";
                        } elseif (empty($_POST['label'])){
                            $update = "Error: No label provided";
                        } elseif ($_POST['defaultValue'] === 'other' && empty($_POST['defaultValue'])){
                            $update = " Error: You have specified a default value but not provided one";
                        } else {
                            if ($_POST['defaultValue'] ==='other'){
                                $default = $_POST['other'];
                            } else{
                                $default = $_POST['defaultValue'];
                            }
                            $this->fields[$_POST['fieldName']] = array('label'=>$_POST['label'],
                                                                        'type'=>$_POST['fieldType'],
                                                                        'default'=>$default,
                                                                        'class'=>$_POST['class']);
                            update_option('extraFieldsinComments', serialize($this->fields));
                            $update = "New field $_POST[fieldName] added";
                        }
                    } else {
                        //back button resubmission
                        $update = "You have already done that!";
                    }//admin referer
                }
            
        }
        
        //get current fields
        $tbody = '';
        
        
        foreach ($this->fields as $name=>$field){
                $tbody .= <<<TB
    <tr>
        <td>{$name}</td>
        <td>{$field['label']}</td>
        <td>{$field['type']}</td>
        <td>{$field['default']}</td>
        <td>{$field['class']}</td>
        <td><form name="form1" method="post" action="{$formUrl}"><input type="hidden" value="$name" name="fieldName" /> <input type="hidden" value="deleteField" name="action"/><input type="submit" value="Delete" name="Submit"/> </form></td>
    </tr>
TB;
        }
        
        
        if (substr($update, 0, 5) == "Error"){
            $newArray = array_merge($array, $_POST);
            print_r($newArray);
            extract($newArray);
        } else {
            extract ($array);
        }
        echo <<<HTML
<style type="text/css">
label {color:#000099; font-style:italic; font-weight:bold;}
</style>
<div class="wrap">
    <h2>Extra Fields for Comments</h2>
    <h3>Add a field</h3>
    {$update}
    <form name="form1" method="post" action="{$formUrl}">
            <p>
            <label for="fieldName">Name:</label><br/>
            <input type="text" name="fieldName" id="fieldName" value="{$fieldName}" />
            </p>
            <p>
            <label for="class">Label</label> <br/>
            <input type="text" name="label" id="class" value="$label" />
            </p>
            <p>
            <label for "fieldType">Field Type</label><br/>
            <input type="radio" name="fieldType" value="text" {$this->getChecked('fieldType', 'text', true)}/>&nbsp;Text<br/>
            <input type="radio" name="fieldType" value="textarea" {$this->getChecked('fieldType', 'textarea')} />&nbsp;Textarea
            </p>
            <p>
            <label for="class">Class</label> <br/>
            <input type="text" name="class" id="class" value="$class" />
            </p>
            <p>
            <label for="defaultValue">Default Value</label><br/>
            <input type="radio" name="defaultValue" value="last submitted" {$this->getChecked('defaultValue', 'last submitted', true)} />&nbsp;Last Submitted Value for the Comment Author<br/>
            <input type="radio" name="defaultValue" value="other" {$this->getChecked('defaultValue', 'other')} />&nbsp;Other <input type="text" name="other" value="$other" /><br/>
            <input type="radio" name="defaultValue" value="none" {$this->getChecked('defaultValue', 'none')}/>&nbsp;None
            <hr />
    
            <p class="submit">
            <input type="submit" name="Submit" value="Create Field" />
            <input type="hidden" name="{$hfn}" value="Y" />
HTML
. wp_nonce_field('add_new_extra_field') . <<<HTML

            </p>
    </form>
    <hr/>
    <h3>Current Fields</h3>
        <p>
        <table class="widefat">
            <thead>
            <tr>
                <th scope="col">Field Name</th>
                <th scope="col">Label</th>
                <th scope="col">Type</th>
                <th scope="col">Default</th>
                <th scope="col">Class</th>
                <th scope="col">&nbsp;</th>
            </tr>
            </thead>
            <tbody>
                {$tbody}
            </tbody>
        </table>
        </p>
    <hr/>
    <h3>Migrate from Extra Comment Fields by IdeaShower</h3>
    <p>Press here to migrate automatically form name="form1" method="post" action="{$formUrl}"><input type="hidden" value="migrate" name="action"/><input type="submit" value="Migrate" name="Submit"/> </form></p>
</div>
HTML;
    }
    

    
    /**
     * method for adding form fields to the comments template
     * uses javascript to restructure the form order.  bit ugly...
     * @return
     */
    public function addFieldToComment(){
        $output = array();
        foreach ($this->fields as $name=>$field){
            $class = empty($field['class']) ? '' : 'class="'.$field['class'].'"';
            switch ($field['type']){
                case "text":
                    $output[] = <<<HTML
<p>
    <label for="{$this->salt}[{$name}]">{$field['label']}</label><br/>
    <input type="text" name="{$this->salt}[{$name}]" value="{$this->getDefaultValue($name)}" id="{$this->salt}_{$name}" $class />
</p>
HTML;
                break;
                case 'textarea':
                    $output[] = <<<HTML
<p>
    <label for="{$this->salt}[{$name}]">{$field['label']}</label><br/>
    <textarea name="{$this->salt}[{$name}]" id="{$this->salt}_{$name}" $class></textarea>
</p>
HTML;
                break;
                
            }
        }
        $_output = json_encode(implode(' ', $output));
        //yuk, here comes the horrible js....
        /*
         * methodology is to grab the form that we are in and work to the textarea (which will be the comment box). then add the $output as nodes after the comment box
         */
        $js = <<<JS
<script type="text/javascript">
/* <![CDATA[ */
function xtraFields_addNodes(){
    var html = $_output;
    var fm = document.getElementById('commentform');
    var contents = fm.innerHTML;
    fm.innerHTML = contents.replace(/<!--EXTRAFIELDS-->/, html);
}
var xtraFields = false;
xtraFields_addNodes();
/* ]]> */
</script>
JS;
    echo $js;
    }
    
    
    /**
     * public method to return the value of a saved extra field.
     *
     * @return
     * @param object $fieldName
     */
    public function getValue($fieldName){
        global $comment;
        if (empty($this->cache[$comment->comment_ID])){
            $this->fillCache($comment->comment_ID);
        }
        if (isset($this->cache[$comment->comment_ID][$fieldName])){
            return $this->cache[$comment->comment_ID][$fieldName];
        } else {
            return '';
        }
    }
    
    /**
     * method that takes the existing comment text and returns the comment text with the extra bits and bobs added
     * @return
     * @param object $commentText
     */
    public function displayExtraFields($commentText){
        
        //do not add extra data if we are in the admin edit menu
        if (is_admin){
            return $commentText;
        }
        global $comment;
        $output = '';
        //get the comment ID to retrieve the metaData
        $extraFields = $this->retrieveData ($comment->comment_ID);
        foreach ($extraFields as $field=>$value){
            //check to make sure whether a field is still wanted
            if ($this->wantedField($field)){
                //create different output templates depending on field type
                switch ($this->fields[$field]['type']){
                    case 'text':
                        $output .= <<<HTML
<div class="extraField">
    <span class="extraFieldLabel_text">{$this->fields[$field]['label']}</span>
    <span class="extraFieldData_text">{$value}</span>
</div>
HTML;
                    break;
                    case 'textarea':
                        $value = nl2br($value);
                        $output .= <<<HTML
<div class="extraField">
    <div class="extraFieldLabel_textarea">{$this->fields[$field]['label']}</div><div class="extraFieldData_textarea">{$value}</div>
</div>
HTML;
                    break;
                } //end switch
            } //end if
        } //end foreach
        return $commentText . $output;
    }
    
    /**
     * public method that runs when a comment is saved to the database
     *
     * method assembles the incoming values into an array to hand off to the update function
     * @return void
     * @param object $commentID
     * @param object $status
     */
    public function validateIncoming($commentID, $status=''){
        $values = array();
        if (!empty($_POST[$this->salt])){
            //we have some incoming data
            if (is_array($_POST[$this->salt])){
                foreach ($_POST[$this->salt] as $key=>$val){
                    
                    if ($this->wantedField($key)){
                        $values[$key] = $val;
                    }
                }
                $this->updateData($commentID, $values, $status);
            }
        }
    }
    
    /**
     * method that actually saves the extra data
     *
     * @return void
     * @param object $commentID
     * @param object $values
     * @param object $status
     */
    public function updateData($commentID, $values, $status=''){
        global $wpdb;
        // if the comment is spam we automatically delete the data (if the option is set)
        if ($status === 'spam' && $this->deleteExtraIfSpam === true){
            $this->deleteData($commentID);
        } else {
            $this->deleteData($commentID);
            $sql = "Insert into $this->table (comment_ID, extraFields) values (%d, %s)";
            $prepare = $wpdb->prepare($sql, $commentID, serialize($values));
        //    echo "prepared sql is $prepare";
            $wpdb->query($prepare);
        }
    }
    
    /**
     * internal method to obtain the current data for a given comment
     *
     * @return array of extra field data.  If no data then empty array returned.
     * @param object $commentID
     */
    public function retrieveData($commentID){
        global $wpdb;
        $array = array();
        $existingOptions = $wpdb->get_var($wpdb->prepare("Select extraFields from {$this->table} where comment_ID=%d", $commentID));
        
        if (!$existingOptions){
            return $array;
        } else {
            return unserialize($existingOptions);
        }
    }
    
    /**
     * method to delete extra fields associated with a comment
     * @return void
     * @param object $commentID
     */
    public function deleteData($commentID){
        global $wpdb;
        $wpdb->query($wpdb->prepare("delete from {$this->table} where comment_ID=%d"));
    }
    
    
    /**
     * method to install the necessary database fields and tables for the plugin
     *
     * @return
     */
    public function init(){
        global $wpdb;
        
        if( 0 != strcasecmp ($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $this->table)), $this->table)) {
            
            $sql = "CREATE TABLE {$this->table} (
                    comment_ID  bigint(20) NOT NULL,
                    extraFields longtext,
                    UNIQUE KEY comment_ID (comment_ID)
                    );";
            require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
            dbDelta($sql);
        }
    }
    
    /**
     * method to auto-fill the fields with a user specified default value or a computed value based on a last known entry
     * @return string
     * @param object $fieldName
     */
    private function getDefaultValue($fieldName){
    //    return $this->fields[$fieldName]['default'];
        switch ($this->fields[$fieldName]['default']){
            case 'last submitted':
                global $user_email, $wpdb;
                if (empty($user_email)){
                    return '';
                }
                $_fieldName = $wpdb->escape($fieldName);
                $sql = "select extraFields from {$this->table} ef join {$wpdb->prefix}comments o on (o.comment_ID = ef.comment_ID) where ef.extraFields like '%%$_fieldName%%' and comment_author_email = %s order by o.comment_date_gmt desc LIMIT 1";
                $sql = $wpdb->prepare($sql, $user_email);
                $result = $wpdb->get_var($sql);
                if (empty($result)){
                    return '';
                }
                $result = unserialize($result);
                if (is_array($result) && isset($result[$fieldName])){
                    return $result[$fieldName];
                } else {
                    return '';
                }
                
            break;
            case 'none':
                return '';
            break;
            default:
                return $this->fields[$fieldName]['default'];
        }
    }
    
    
    /**
     * method to migrate data and meta-data stored in Extra Comment Fields by ideashower
     * @return
     */
    private function migrate(){
        global $wpdb;
        $firstTime = true;
        $ot = $wpdb->prefix."comments_extra";
        $nt = $this->table;
        
        //get old table values
        $results = $wpdb->get_results("select * from $ot", ARRAY_A);
        $fields = array();
        foreach($results as $r){
            $commentID = $r['commentID'];
            unset($r['commentID']);
            $curValues = $this->retrieveData($commentID);
            $values = array_merge($r, $curValues);
            $values = serialize ($values);
            $this->upddateData($commentID, $values);
            if ($firstTime){
                $keys = array_keys($r);
                $keyCache = array();
                foreach ($keys as $key){
                    if ($this->wantedField($key)){
                        //do nothing
                    } else {
                        $this->fields[$key] = array ('class'=>'',
                                                    'label'=>$key,
                                                    'default'=>'none',
                                                    'type'=>'text');
                    }
                }
                update_option('extraFieldsinComments', serialize($this->fields));
                $firstTime = false;
            }
        }
        return true;
    }
    
    /**
     * method used to make radio and checkboxes sticky
     * @return
     * @param object $field
     * @param object $value
     */
    private function getChecked($field, $value, $default = false){
        if (empty($_POST[$field])){
            if ($default){
                return 'checked="checked"';
            } else {
                return '';
            }
        } else {
            if ($_POST[$field] == $value){
                return 'checked="checked"';
            } else {
                return '';
            }
        }
    }
    
    /**
     * private method to create a cache for performance optimisation
     *
     * @return
     * @param object $commentID
     */
    private function fillCache($commentID){
        $this->cache[$commentID] = $this->retrieveData($commentID);
    }
    
    /**
     * method to discard stored fields that are no longer required for display
     *
     * @return
     * @param object $field
     */
    private function wantedField($field){
        return array_key_exists($field, $this->fields);
    }
}
endif;
$extraCommentFields = new extraComments();
register_activation_hook(__FILE__, array(&$extraCommentFields, 'init'));


    

?>

RE: Include additional field in comments for logged in users

(OP)
No sweat, Justin! This is perfect for my current requirements. I just want to get this all online now - migration of the old log pages is taking the longest and I'm afraid that's a manual job. Liz has just returned to the UK as well so I'm on me tod. Was hoping to get it all live within the next week. With your help I'm almost there. Cheers.

RE: Include additional field in comments for logged in users

the code above has the migration in it for the locations/extra fields.

if you want a hand migrating the old blog to the new let me know.  i guarantee that it can be automated: the beauty of the WP API....  if you'd rather do that bit off line, then feel free to contact me. you can get my address through rathercurious.net.
 

Red Flag This Post

Please let us know here why this post is inappropriate. Reasons such as off-topic, duplicates, flames, illegal, vulgar, or students posting their homework.

Red Flag Submitted

Thank you for helping keep Tek-Tips Forums free from inappropriate posts.
The Tek-Tips staff will check this out and take appropriate action.

Reply To This Thread

Posting in the Tek-Tips forums is a member-only feature.

Click Here to join Tek-Tips and talk with other members!

Resources

Close Box

Join Tek-Tips® Today!

Join your peers on the Internet's largest technical computer professional community.
It's easy to join and it's free.

Here's Why Members Love Tek-Tips Forums:

Register now while it's still free!

Already a member? Close this window and log in.

Join Us             Close