Skip to content

Instantly share code, notes, and snippets.

@boonebgorges
Created April 16, 2012 21:09
Show Gist options
  • Save boonebgorges/2401529 to your computer and use it in GitHub Desktop.
Save boonebgorges/2401529 to your computer and use it in GitHub Desktop.
Add an "Other" option at the end of a list of BuddyPress profile checkbox options, where users can enter custom text
<?php
/**
* Add an 'Other' type to xprofile fields
*
* @link https://buddypress.trac.wordpress.org/ticket/3775
* @link http://redmine.gc.cuny.edu/issues/1199
*/
class CAC_Xprofile_Other {
function __construct() {
add_action( 'xprofile_field_additional_options', array( &$this, 'render_admin' ) );
add_action( 'xprofile_fields_saved_field', array( &$this, 'save_admin_field' ) );
add_action( 'bp_get_the_profile_field_options_checkbox', array( &$this, 'render_field' ), 10, 5 );
add_action( 'xprofile_data_after_save', array( &$this, 'save_field_data' ) );
// Call early to beat race condition for auto-links
add_action( 'bp_get_the_profile_field_value', array( &$this, 'render_public_field' ), 5, 3 );
}
function render_admin() {
$field_id = isset( $_GET['field_id'] ) ? (int)$_GET['field_id'] : NULL;
$other_toggle = 'yes' == bp_xprofile_get_meta( $field_id, 'field', 'cac_other_field' );
?>
<div id="titlediv">
<h3>'Other' field</h3>
<label for="cac-other-field">Add an "Other" option at the end of this list (a checkbox/radio button + a text field)?</label><br />
<input type="radio" name="cac-other-field" value="yes" <?php checked( $other_toggle, true ) ?>/> Yes<br />
<input type="radio" name="cac-other-field" value="no" <?php checked( !$other_toggle, true ) ?>/> No
</div>
<?php
}
function save_admin_field( $field ) {
if ( isset( $_POST['cac-other-field'] ) ) {
// When creating a new field, no field_id will have been set yet. We'll
// look it up based on the $field object passed to the hook
if ( empty( $this->field_id ) ) {
$this->field_id = BP_XProfile_Field::get_id_from_name( $field->name );
}
$data = 'yes' == $_POST['cac-other-field'] ? 'yes' : 'no';
bp_xprofile_update_field_meta( $this->field_id, 'cac_other_field', $data );
}
}
function render_field() {
$field_id = func_get_arg( 2 );
$field = wp_cache_get( 'xprofile_parent_field_' . $field_id, 'bp' );
if ( !$field ) {
$field = new BP_XProfile_Field( $field_id );
wp_cache_set( 'xprofile_parent_field_' . $field_id, $field, 'bp' );
}
$siblings = wp_cache_get( 'xprofile_siblings_' . $field_id, 'bp' );
if ( !$siblings ) {
$siblings = $field->get_children();
wp_cache_set( 'xprofile_siblings_' . $field_id, $siblings, 'bp' );
}
// Only continue if this is the last in the list
$position = func_get_arg( 4 ) + 1;
if ( $position != count( $siblings ) ) {
return func_get_arg( 0 );
}
// Only continue if the Other field is enabled for this item
if ( 'yes' != bp_xprofile_get_meta( $field_id, 'field', 'cac_other_field' ) ) {
return func_get_arg( 0 );
}
$current_value = new BP_XProfile_ProfileData( $field_id, bp_displayed_user_id() );
if ( isset( $current_value->id ) ) {
$is_checked = 'yes' == bp_xprofile_get_meta( $current_value->id, 'data', 'cac_other_field' );
$other_text = bp_xprofile_get_meta( $current_value->id, 'data', 'cac_other_field_text' );
} else {
$is_checked = false;
$other_text = '';
}
/*
$field_name = 'field_' . $field_id . '_other';
if ( 'checkbox' == $field->type ) {
$field_name .= '[]';
}
*/
$checked = $is_checked ? ' checked="checked" ' : '';
$html = func_get_arg( 0 ) . '<label><input type="' . $field->type . '" name="field_' . $field_id . '[other]" id="field_' . $field_id . '_other" value="cac_other_value"' . $checked . '> Other </label> <input class="other-text" type="text" name="field_' . $field_id . '_other_text" value="' . esc_attr( $other_text ) . '" />';
return $html;
}
function save_field_data( $fielddata ) {
// Groan
if ( 'yes' != bp_xprofile_get_meta( $fielddata->field_id, 'field', 'cac_other_field' ) ) {
return;
}
$fid = $fielddata->field_id;
$current_value = new BP_XProfile_ProfileData( $fid, bp_displayed_user_id() );
if ( isset( $_POST['field_' . $fid] ) && is_array( $_POST['field_' . $fid] ) && !empty( $current_value->id ) ) {
if( !empty( $_POST['field_' . $fid]['other'] ) ) {
if ( isset( $_POST['field_' . $fid . '_other_text'] ) ) {
bp_xprofile_update_meta( $current_value->id, 'data', 'cac_other_field_text', $_POST['field_' . $fid . '_other_text'] );
bp_xprofile_update_meta( $current_value->id, 'data', 'cac_other_field', 'yes' );
}
} else {
bp_xprofile_update_meta( $current_value->id, 'data', 'cac_other_field', 'no' );
}
}
}
function render_public_field( $html, $type, $fid ) {
if ( in_array( $type, array( 'textbox', 'textarea' ) ) ) {
return $html;
}
$current_value = new BP_XProfile_ProfileData( $fid, bp_displayed_user_id() );
$is_checked = 'yes' == bp_xprofile_get_meta( $current_value->id, 'data', 'cac_other_field' );
if ( $is_checked ) {
$other_text = bp_xprofile_get_meta( $current_value->id, 'data', 'cac_other_field_text' );
if ( $other_text ) {
$html .= ', ' . $other_text;
}
}
return $html;
}
}
new CAC_Xprofile_Other();
@goyelle
Copy link

goyelle commented Aug 30, 2018

Hi,
I needed to add an "Other" option with an input to a radio field in the profile part, so I've found your code (line 27 you indicate "checkbox/radio button"). Thanks for your code, because it is Wonderland for me, regarding my lack of knowledge. I try to understand it... But I can't make it work, the message "an error occurred while your informations were updated. Please try again" (this is a translation from French...) when I want to save a profile with the "other" option checked or with the input filled in. Maybe it's because of the BuddyPress version (3.1.0 now), or something else. Do you have a clue how to solve this?

And two things went in the way of getting what I need:

  1. wether it works for checkboxes only and not for radio fields or I just don't know how to use your code (I can see in line 12 the "add_action" for "bp_get_the_profile_field_options_checkbox" but not for radio button).
    Do you know how to do the same for a radio button?
  2. the input element created for the "Other" option is always shown. I don't find it very "clean" and the input can be filled without checking the checkbox.

I've worked "a little" on this number 2 (and I'm just beginning to use JavaScript again and I had a very low level so I'm just trying to figure it out by making attempts) - it took me a couple of hours...

So far, using JavaScript, I've managed to show the input element only when the "Other" option is checked, and hide it when it's not, but I have absolutely no skill to judge the quality of the code.
I copy my changes here, if you could have a look and tell me if it's ok to change your code that way, that would be tremendous, or maybe this would at least help someone to find a clean solution.

What I've done:

  • I've added an ID to the input element created for the "Other" option, and changed its type from "text" to "hidden" because changing the display to "none" doesn't work, the input CSS "inline-block" overrules.
  • The script for the event "onClick" changes the type from "hidden" to "text" when the checkbox is checked and inversely (function: "onClickOther").
  1. I changed line 91 like that:
    $html = func_get_arg( 0 ) . '<label><input type="' . $field->type . '"id="field_' . $field_id . '[other]_id" name="field_' . $field_id . '[other]" value="cac_other_value"' . $checked . ' onClick="onClickOther('.$field_id.')"> Other </label> <input class="other-text" type="hidden" name="field_' . $field_id . '_other_text" id="field_' . $field_id . '_other_text_id" value="' . esc_attr( $other_text ) . '" />';

  2. I created a js file in a js folder in my child theme folder:
    child-theme-folder/js/myfile.js

  3. I added this function at the end of my functions.php file (in my child theme folder) to call the script:

`// enqueue javascript
function add_js(){
wp_enqueue_script( 'onClickOther',
get_stylesheet_directory_uri() . '/js/myfile.js',
array() );
}

add_action( 'wp_footer', 'theme_js' );`

Maybe there is a solution elsewhere, I haven't found it yet. But it was an opportunity to meet JavaScript again! Now I would love this code to work.
Thanks in advance!

@amit834
Copy link

amit834 commented Oct 11, 2021

Other option not able to save data. #Boone Gorges please suggest how to do that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment