Support » Plugin: Buddypress Xprofile Custom Fields Type » How To Add textarea field to buddypress-xprofile-custom-fields-type?

  • Resolved johnywhy

    (@johnywhy)


    using xprofile-custom-fields-type Version: 2.4.1

    hi

    i’m trying to add a textarea field (multi-line, plain-text).

    i’m inspecting your files in ‘buddypress-xprofile-custom-fields-type’. Hope that’s ok, donmik!

    trying to figure out which files to edit, so i searched for ‘datepicker’. Planning to imitate the datepicker field.

    i found ‘datepicker’ in:

    bp-xprofile-custom-fields-type.php
    classes\Bxcft_Field_Type_Datepicker.php
    lang\buddypress-xprofile-custom-fields-type.pot
    lang\en_US.mo
    lang\en_US.po

    (ignoring the non-english files for the moment).

    i simply duplicated all the ‘datepicker’ code-chunks in those files, and replaced ‘datepicker’ with ‘textarea’.

    also duplicated the file ‘classes\Bxcft_Field_Type_Datepicker.php’, renamed it ‘Bxcft_Field_Type_Textarea.php’.

    and so on and so forth.

    also removed any date-specific code i found, when i turning the datepicker into a textarea field.

    then i zipped it, uploaded to wordpress, activated, and added my new Textarea field to a form.

    i actually got no errors, and actually got a text field on my registration form!

    unfortunately, it’s only a one-line textbox, not a multiline textarea.

    hrm. In inspector, the displayed field is:

    <input type=”string”>

    so something in donmik’s code, or BP, or WP, is causing this to render as an <input> rather than <textarea>

    you can download my zip here:
    https://www.dropbox.com/s/nx0ox3weg5khlpi/buddypress-xprofile-custom-fields-type-JW-TEXTAREA.zip?dl=0

    i welcome any suggestions!

    also posted here-
    https://buddypress.org/support/topic/how-to-get-plaintext-multiline-field/#post-249700

    thx!!!

    https://wordpress.org/plugins/buddypress-xprofile-custom-fields-type/

Viewing 11 replies - 1 through 11 (of 11 total)
  • i also edited the .po file, and generated a new .mo from that.

    In case anyone is wondering why we would want a plaintext field:

    We don’t want our members formatting their bios with bold text, big fonts, colors, etc etc. We want our CSS to control presentation.

    We don’t want our members formatting their bios with bold text, big fonts, colors, etc etc. We want our CSS to control presentation.

    — it’s for this reason that i suggest that <textarea> is an important omission in BP fields.

    But BP IS AWESOME, AND THANK YOU to all the devs who built it.

    THANK YOU to donmik for the fantastic extra fields, GREAT PLUGINS!!

    hope you’ll be willing to help me solve this (i know this is not the right way to build a plugin 🙂

    Plugin Author Miguel López

    (@atallos)

    Hi,

    I believe you made a lot of work but it was an easier solution. You can deactivate richtext if you want using the following filter: “bp_xprofile_is_richtext_enabled_for_field”.

    So if you want to disable richtext for all fields, just copy and paste the following code inside your functions.php of your theme:

    function bp_disable_richtext($enabled, $field_id) {
    	$enabled = false;
    	return $enabled;
    }
    add_filter('bp_xprofile_is_richtext_enabled_for_field', 'bp_disable_richtext', 10, 2);

    If you want to disable only for one field, check against $field_id.

    In your case, your new field is not working because you have copied datepicker and datepicker is an input. If you want to create your own textarea I recommend you to copy buddypress textarea original class located in /wp-content/plugins/buddypress/bp-xprofile/classes/.

    You can copy and paste class-bp-xprofile-field-type-textarea.php and disable richtext if you want but I recommend you strongly to use the filter.

    Thanks!

    fantastic answer!

    thx for explaining why copying datepicker didn’t work, i guess i used the wrong field as a model! i used that because i wanted the html5 textarea. Will your filter give the html5 textarea?

    your solution is slightly different from this other one, which helps me learn.
    https://buddypress.org/support/topic/how-to-get-plaintext-multiline-field/#post-249715

    i want to create a “Rich text” checkbox into the userfield editor, so users can enable/disable in the GUI. That will require:
    – code to create the option checkbox in the editor.
    – code to display the textarea on the front-end.

    i decided to imitate the structure of the decimal control. I searched your plugin files for ‘decimal_number_option’ (which is the ID of the decimal picker html element in the editor). But not found!

    Which makes me think you’re doing some concatenation of the string ‘_option’ to ‘decimal_number’ in one of your files, to get the full ‘decimal_number_option’ string. So i checked out the birthdate php class, and sure enough found the function admin_new_field_html contains:

    ....
                    while ( isset( $_POST[$type . '_option'][$i] ) ) {
                        $is_default_option = true;
    
                        $options[] = (object) array(
                            'id'                => -1,
                            'is_default_option' => $is_default_option,
                            'name'              => sanitize_text_field( stripslashes( $_POST[$type . '_option'][$i] ) ),
    ....

    nice work, donmik! very smart code! So i’m thinking must combine this code with the filter you offered above, maybe.

    I also searched files for ‘birthdate_option’ (ID of the decimal picker html element in the editor), and that one does show up in admin.js, along with some other fields, but not all fields. I guess some fields need some js handling?

    I’m thinking my multi-line richtext checkbox should be defined in the buddypress plugin, not your Custom Fields plugin, because the multi-line field is part of buddypress core, not your plugin. Right?

    Feel free to share some clues 🙂

    Plugin Author Miguel López

    (@atallos)

    I’ve just been playing around with this, so I have the code working. I’m going to explain a little bit how this is working.

    I’ve copied the buddypress class of Textarea inside my plugin and created a class named “Bxcft_Field_Type_Textarea”. This class will extend the original class “BP_Xprofile_Field_Type_Textarea”.

    1. Constructor.
    We need to support options:
    $this->supports_options = true;

    This is necessary to display the checkbox to disabled richtext.

    2. Override “admin_new_field_html” method.

    This method is responsible of display the checkbox form. So with this code:

    public function admin_new_field_html (\BP_XProfile_Field $current_field, $control_type = '')
            {
                $type = array_search( get_class( $this ), bp_xprofile_get_field_types() );
                if ( false === $type ) {
                    return;
                }
    
                $class            = $current_field->type != $type ? 'display: none;' : '';
                $current_type_obj = bp_xprofile_create_field_type( $type );
    
                $options = $current_field->get_children( true );
                if ( ! $options ) {
                    $options = array();
                    $i       = 1;
                    while ( isset( $_POST[$type . '_option'][$i] ) ) {
                        $is_default_option = true;
    
                        $options[] = (object) array(
                            'id'                => -1,
                            'is_default_option' => $is_default_option,
                            'name'              => sanitize_text_field( stripslashes( $_POST[$type . '_option'][$i] ) ),
                        );
    
                        ++$i;
                    }
    
                    if ( ! $options ) {
                        $options[] = (object) array(
                            'id'                => -1,
                            'is_default_option' => false,
                            'name'              => '',
                        );
                    }
                }
            ?>
                <div id="<?php echo esc_attr( $type ); ?>" class="postbox bp-options-box" style="<?php echo esc_attr( $class ); ?> margin-top: 15px;">
                    <h3><?php esc_html_e( 'Disable richtext:', 'bxcft' ); ?></h3>
                    <div class="inside">
                        <p>
                            <?php _e('Check this if you want to disable richtext for this field:', 'bxcft'); ?>
                            <input type="hidden" name="<?php echo esc_attr( "{$type}_option[0]" ); ?>" id="<?php echo esc_attr( "{$type}_option0" ); ?>" value="enable_richtext" />
                            <input type="checkbox" name="<?php echo esc_attr( "{$type}_option[1]" ); ?>" id="<?php echo esc_attr( "{$type}_option1" ); ?>" value="disable_richtext"
                                   <?php if ($options[0]->name == 'disable_richtext') : ?>checked="checked"<?php endif; ?>/>
                        </p>
                    </div>
                </div>
            <?php
            }

    We will display a checkbox to disable richtext. With this code, the default behavior is enable richtext. User has to disable it checking the checkbox. If you want default behavior to be richtext disable. You just have to change options “enable_richtext” by “disable_richtext”.

    3. Replace code inside “admin_field_html”

    This method is responsible of display the field inside the list of profile fields in wordpress admin. Just replace this line:

    $richtext_enabled = bp_xprofile_is_richtext_enabled_for_field();

    With this:

    global $field;
            $richtext_enabled = bp_xprofile_is_richtext_enabled_for_field();
            $options = $field->get_children();
            foreach ($options as $option) {
                if ($option->name == 'disable_richtext') {
                    $richtext_enabled = false;
                    break;
                }
            }

    This code is looking for the “disable_richtext” option of $field. If it exists, it will disable the richtext ($richtext_enabled = false;).

    4. Replace code in “edit_field_html”

    This method display the field in wordpress frontend edit profile form.

    Replace this:
    $richtext_enabled = bp_xprofile_is_richtext_enabled_for_field();

    With:

    global $field;
    $richtext_enabled = bp_xprofile_is_richtext_enabled_for_field();
            $options = $field->get_children();
            foreach ($options as $option) {
                if ($option->name == 'disable_richtext') {
                    $richtext_enabled = false;
                    break;
                }
            }

    This code do the same thing.

    Now the admin.js changes:

    You have to implement the same behavior I’ve done for birthdate field. If you look at the “admin_new_field_html”, I’ve created two input fields. One is hidden and is “enable_richtext”. The other one is checkbox and is “disable_richtext”. When you check “disable_richtext” and click on update, we need to remove the hidden field before saving data because buddypress will save all the field options so if you send with the form the hidden option buddypress will save: “enable_richtext” AND “disable_richtext”, but we only want one of them.

    So you can do this way:

    1. Modify my original “bxcft_remove_empty_checkbox”, replace with:

    function bxcft_remove_empty_checkbox($, type) {
        if ($('#' + type + '_option1').is(':checked')) {
            $('#' + type + '_option0').remove();
        }
    }

    This function can be used now for any type give “type” param. So I can reuse it for our new textarea field.

    2. Add below:

    else if ($('select#fieldtype').val() == 'birthdate') {
                bxcft_remove_empty_checkbox($, 'birthdate');
            }

    This code:

    else if ($('select#fieldtype').val() == 'textarea') {
                bxcft_remove_empty_checkbox($, 'textarea');
            }

    The last thing we have to do is add the new field and register new type of field. You have to do it in “bp-xprofile-custom-fields-type.php”.

    1. In init() method, add this require_once:

    require_once( 'classes/Bxcft_Field_Type_Textarea.php' );

    2. In bxcft_get_field_types method, add the new type to the array $new_fields:

    'textarea' => 'Bxcft_Field_Type_Textarea',

    All done! This should work.

    The last problem you have to think is to do your own plugin with this… because if you still want to use my plugin. Your code will be overriden so I recommend you to create your own plugin.

    It’s not hard, you can copy and paste my plugin and delete all you don’t need:

    • Remove all classes (not yours) you are not using from classes folder.
    • Remove from js folder, all files (not admin.js).
    • Inside bp-xprofile-custom-fields-type.php, Remove all methods but:
      – construct
      – init
      – admin_init
      – admin_notices
      – bxcft_get_field_types
      – update
      – activate
      – deactivate

      You have to remove from construct all the add_filter or add_action you don’t need (all methods you have removed). From init, remove all classes you don’t require anymore. Remove the javascript you don’t need to enqueue…

    • In admin.js, remove all code but the function and code for your new type of field.
    • Replace everywhere you see bxcft with your own plugin name or plugin abbreviation.

    I hope you will be able to achieve what you want with this explanation. If you have any problem, I can send you the code. Feel free to ask.

    Plugin Author Miguel López

    (@atallos)

    I’ve uploaded the plugin I created to github. Feel free to use it.

    I will probably writing an article about this in my blog tomorry so if you are interested check my blog tomorrow 🙂

    absolutely, fantastic, donmik!

    thx for suggesting that i make my own plugin with this, but that would not be right– you built it!

    hope you include this feature in your next release!

    many thx!

    wow, thx donmik, for listing me as contributor in the new plugin!

    Hi

    i’m still learning, but i have some thoughts about the new plugin:

    It seems to me that if we’re extending a class, then it’s safer to let the parent execute it’s own code, instead of copying the parent code verbatim to our own class. I believe a benefit of inheritance is that you inherit the parent’s functions, and only new code should go in the child– just as you do in the constructor.

    So in the function admin_field_html, i suggest this change:

    ...
        // Original code of buddypress class.
        // Call the parent
        parent::admin_field_html();
    
        // and remove code copied from the parent
    
        ...

    ====
    same thing in function edit_field_html:

    ...
    	// Original code of buddypress class.
    	// Call the parent.
        parent::edit_field_html();
    
        // and remove code copied from the parent
        ...

    ====
    function admin_field_html is a bit different. here’s your current code:

    ...
        // The original $richtext_enabled flag.
        $richtext_enabled = bp_xprofile_is_richtext_enabled_for_field();
    
        // I'm looking inside the options to check if the checkbox "disabled_richtext
        // for this field is checked.
        $options = $field->get_children();
        foreach ($options as $option) {
            if ($option->name == 'disable_richtext') {
            	// Found it, so $richtext_enabled should be false
            	$richtext_enabled = false;
            	// Stop looking for it, just in case.
            	break;
            	}
        }
    
        // Original code of buddypress class (copied from parent class)

    Like the previous function, you’re again inserting the full body of the parent fx. So again, i want to do a call to the parent fx, instead of copying the parent code into your fx.

    Problem is, unlike the previous examples, we can’t just insert a call to the parent, because your code is inserted in the *middle* of the parent fx.

    // First you do this line, copied from the parent:
    $richtext_enabled = bp_xprofile_is_richtext_enabled_for_field();
    // then your own code, to test the checkbox.
    // and then you execute the rest of the parent code.

    This makes me think the parent classes are not consistently-structured.

    Is it necessary to do $richtext_enabled before your code? If we can put that after your code, then we can call the parent fx instead of copying it.

    thx!

    Plugin Author Miguel López

    (@atallos)

    Thanks again for checking my code and ask questions.

    We cannot use parent calls because buddypress parent method overrides the value of $richtext_enabled. So our code will be useless.

    But, you’re right, my first version of this plugin is not the best. Overriding and copying buddypress functions is not the best way to achieve this. Especially when we have “bp_xprofile_is_richtext_enabled_for_field” filter ready to use.

    So, I’ve changed my code. Now I’m not overriding edit_field_html or admin_field_html. What I’m doing is use the previous filter.

    In the main file, I’ve added this line to “init” method:

    add_filter( 'bp_xprofile_is_richtext_enabled_for_field', array($this, 'bpxct_disable_richtext'), 10, 2 );

    And at the end of the class, I’ve added the new method to disable richtext:

    public function bpxct_disable_richtext($enabled, $field_id) {
                // Init $field object with $field_id.
                $field = new BP_XProfile_Field($field_id);
                if (!$field) {
                    return $enabled;
                }
    
                // I'm looking inside the options to check if the checkbox "disabled_richtext
                // for this field is checked.
                $options = $field->get_children();
                foreach ($options as $option) {
                    if ($option->name == 'disable_richtext') {
                        // Found it, so $richtext_enabled should be false
                        $enabled = false;
                        // Stop looking for it, just in case.
                        break;
                    }
                }
    
                return $enabled;
            }

    Of course, I’ve removed edit_field_html and admin_field_html methods in our custom textarea class.

    I believe this is the better way to do this. You can download the new version in github.

    Un-be-liev-able. You ROCK, donmik!. Ok, now i’ll have to study this 🙂

Viewing 11 replies - 1 through 11 (of 11 total)
  • You must be logged in to reply to this topic.