Skip to:
Content

BuddyPress.org

Ticket #6789: 6789.03.patch

File 6789.03.patch, 18.4 KB (added by Offereins, 2 years ago)

.01 + .02 + first pass at multiple row data

  • src/bp-xprofile/bp-xprofile-filters.php

    diff --git a/src/bp-xprofile/bp-xprofile-filters.php b/src/bp-xprofile/bp-xprofile-filters.php
    index a0c9481..3542cb5 100644
    a b function xprofile_filter_kses( $content, $data_obj = null ) { 
    156156 * @since 1.2.6
    157157 *
    158158 * @param string      $field_value Field value being santized.
    159  * @param int         $field_id    Field ID being sanitized.
     159 * @param int         $data_id     Data ID being sanitized.
    160160 * @param bool        $reserialize Whether to reserialize arrays before returning. Defaults to true.
    161161 * @param object|null $data_obj    The BP_XProfile_ProfileData object.
    162162 * @return string
    163163 */
    164 function xprofile_sanitize_data_value_before_save( $field_value, $field_id = 0, $reserialize = true, $data_obj = null ) {
     164function xprofile_sanitize_data_value_before_save( $field_value, $data_id = 0, $reserialize = true, $data_obj = null ) {
    165165
    166166        // Return if empty.
    167167        if ( empty( $field_value ) ) {
  • src/bp-xprofile/bp-xprofile-functions.php

    diff --git a/src/bp-xprofile/bp-xprofile-functions.php b/src/bp-xprofile/bp-xprofile-functions.php
    index 21ffe7b..49d6a3a 100644
    a b function xprofile_get_field_data( $field, $user_id = 0, $multi_format = 'array' 
    361361
    362362        $values = maybe_unserialize( BP_XProfile_ProfileData::get_value_byid( $field_id, $user_id ) );
    363363
    364         if ( is_array( $values ) ) {
     364        // Consider multiple values
     365        if ( bp_xprofile_field_supports_multiple_values( $field_id ) ) {
     366                $values = array_map( 'maybe_unserialize', $values );
    365367                $data = array();
    366368                foreach( (array) $values as $value ) {
    367369
    function xprofile_set_field_data( $field, $user_id, $value, $is_required = false 
    464466        $field           = new BP_XProfile_ProfileData();
    465467        $field->field_id = $field_id;
    466468        $field->user_id  = $user_id;
    467         $field->value    = maybe_serialize( $value );
     469
     470        // Consider multiple values
     471        if ( bp_xprofile_field_supports_multiple_values( $field_id ) ) {
     472                $field->value = array_map( 'maybe_serialize', $value );
     473        } else {
     474                $field->value = maybe_serialize( $value );
     475        }
    468476
    469477        return $field->save();
    470478}
    function xprofile_get_random_profile_data( $user_id, $exclude_fullname = true ) 
    638646 * Formats a profile field according to its type. [ TODO: Should really be moved to filters ]
    639647 *
    640648 * @since 1.0.0
     649 * @since 2.9.0 The `$field_value` parameter can be an array.
    641650 *
    642  * @param string $field_type  The type of field: datebox, selectbox, textbox etc.
    643  * @param string $field_value The actual value.
     651 * @param string       $field_type  The type of field: datebox, selectbox, textbox etc.
     652 * @param string|array $field_value The actual value.
    644653 * @return string|bool The formatted value, or false if value is empty.
    645654 */
    646655function xprofile_format_profile_field( $field_type, $field_value ) {
    function bp_xprofile_is_richtext_enabled_for_field( $field_id = null ) { 
    11301139}
    11311140
    11321141/**
     1142 * Does this profile field support multiple values?
     1143 *
     1144 * @since 2.9.0
     1145 *
     1146 * @param int|null $field_id Optional. Default current field ID.
     1147 * @return bool              Whether the field supports multiple values
     1148 */
     1149function bp_xprofile_field_supports_multiple_values( $field_id = null ) {
     1150        if ( ! $field_id ) {
     1151                $field_id = bp_get_the_profile_field_id();
     1152        }
     1153
     1154        $field = xprofile_get_field( $field_id, null, false );
     1155
     1156        $supports = false;
     1157        if ( $field instanceof BP_XProfile_Field ) {
     1158                $supports = (bool) $field->type_obj->supports_multiple_values;
     1159        }
     1160
     1161        /**
     1162         * Filters whether the given field supports multiple values.
     1163         *
     1164         * @since 2.9.0
     1165         *
     1166         * @param bool $supports True if the field supports multiple values, otherwise false.
     1167         * @param int  $field_id ID of the field.
     1168         */
     1169        return (bool) apply_filters( 'bp_xprofile_field_supports_multiple_values', $supports, $field_id );
     1170}
     1171
     1172/**
    11331173 * Get visibility levels out of the $bp global.
    11341174 *
    11351175 * @since 1.6.0
  • src/bp-xprofile/bp-xprofile-template.php

    diff --git a/src/bp-xprofile/bp-xprofile-template.php b/src/bp-xprofile/bp-xprofile-template.php
    index 63723da..ec7c791 100644
    a b function bp_the_profile_field_visibility_level_label() { 
    907907 * Return unserialized profile field data.
    908908 *
    909909 * @since 1.0.0
     910 * @since 2.9.0 The `$value` parameter can be an array.
    910911 *
    911  * @param string $value Content to maybe unserialize.
     912 * @param string|array $value Content to maybe unserialize.
    912913 * @return string
    913914 */
    914915function bp_unserialize_profile_field( $value ) {
    915         if ( is_serialized($value) ) {
    916                 $field_value = maybe_unserialize($value);
     916        if ( is_serialized( $value ) || is_array( $value ) ) {
     917                $field_value = maybe_unserialize( $value );
    917918                $field_value = implode( ', ', $field_value );
    918919                return $field_value;
    919920        }
  • src/bp-xprofile/classes/class-bp-xprofile-field-type-checkbox.php

    diff --git a/src/bp-xprofile/classes/class-bp-xprofile-field-type-checkbox.php b/src/bp-xprofile/classes/class-bp-xprofile-field-type-checkbox.php
    index 7267ad9..a4a2167 100644
    a b class BP_XProfile_Field_Type_Checkbox extends BP_XProfile_Field_Type { 
    2828                $this->category = _x( 'Multi Fields', 'xprofile field type category', 'buddypress' );
    2929                $this->name     = _x( 'Checkboxes', 'xprofile field type', 'buddypress' );
    3030
     31                $this->supports_multiple_values   = true;
    3132                $this->supports_multiple_defaults = true;
    3233                $this->accepts_null_value         = true;
    3334                $this->supports_options           = true;
  • src/bp-xprofile/classes/class-bp-xprofile-field-type-multiselectbox.php

    diff --git a/src/bp-xprofile/classes/class-bp-xprofile-field-type-multiselectbox.php b/src/bp-xprofile/classes/class-bp-xprofile-field-type-multiselectbox.php
    index 5ecaa10..af92d00 100644
    a b class BP_XProfile_Field_Type_Multiselectbox extends BP_XProfile_Field_Type { 
    2828                $this->category = _x( 'Multi Fields', 'xprofile field type category', 'buddypress' );
    2929                $this->name     = _x( 'Multi Select Box', 'xprofile field type', 'buddypress' );
    3030
     31                $this->supports_multiple_values   = true;
    3132                $this->supports_multiple_defaults = true;
    3233                $this->accepts_null_value         = true;
    3334                $this->supports_options           = true;
  • src/bp-xprofile/classes/class-bp-xprofile-field-type.php

    diff --git a/src/bp-xprofile/classes/class-bp-xprofile-field-type.php b/src/bp-xprofile/classes/class-bp-xprofile-field-type.php
    index f282a82..75035dd 100644
    a b abstract class BP_XProfile_Field_Type { 
    6666        public $supports_options = false;
    6767
    6868        /**
     69         * If allowed to store multiple values.
     70         *
     71         * @since 2.9.0
     72         * @var bool Does this field support multiple values? e.g. multiselectbox, checkbox.
     73         */
     74        public $supports_multiple_values = false;
     75
     76        /**
    6977         * If allowed to support multiple options as default.
    7078         *
    7179         * @since 2.0.0
  • src/bp-xprofile/classes/class-bp-xprofile-profiledata.php

    diff --git a/src/bp-xprofile/classes/class-bp-xprofile-profiledata.php b/src/bp-xprofile/classes/class-bp-xprofile-profiledata.php
    index 62603e7..9dfdbe8 100644
    a b class BP_XProfile_ProfileData { 
    8989                        $bp = buddypress();
    9090
    9191                        $sql         = $wpdb->prepare( "SELECT * FROM {$bp->profile->table_name_data} WHERE field_id = %d AND user_id = %d", $field_id, $user_id );
    92                         $profiledata = $wpdb->get_row( $sql );
     92                        $profiledata = $wpdb->get_results( $sql );
    9393
    9494                        if ( $profiledata ) {
    9595                                wp_cache_set( $cache_key, $profiledata, 'bp_xprofile_data' );
    class BP_XProfile_ProfileData { 
    9797                }
    9898
    9999                if ( $profiledata ) {
    100                         $this->id           = (int) $profiledata->id;
    101                         $this->user_id      = (int) $profiledata->user_id;
    102                         $this->field_id     = (int) $profiledata->field_id;
    103                         $this->value        = stripslashes( $profiledata->value );
    104                         $this->last_updated = $profiledata->last_updated;
     100                        $this->id           = (int) $profiledata[0]->id;
     101                        $this->user_id      = (int) $profiledata[0]->user_id;
     102                        $this->field_id     = (int) $profiledata[0]->field_id;
     103                        $this->last_updated = $profiledata[0]->last_updated;
     104
     105                        // Collect multiple values per field
     106                        if ( bp_xprofile_field_supports_multiple_values( $this->field_id ) ) {
     107                                $this->value    = array_map( 'stripslashes', wp_list_pluck( $profiledata, 'value' ) );
     108                        } else {
     109                                $this->value    = stripslashes( $profiledata[0]->value );
     110                        }
    105111
    106112                } else {
    107113                        // When no row is found, we'll need to set these properties manually.
    class BP_XProfile_ProfileData { 
    184190
    185191                $bp = buddypress();
    186192
    187                 $this->user_id      = apply_filters( 'xprofile_data_user_id_before_save',      $this->user_id,         $this->id );
    188                 $this->field_id     = apply_filters( 'xprofile_data_field_id_before_save',     $this->field_id,        $this->id );
    189                 $this->value        = apply_filters( 'xprofile_data_value_before_save',        $this->value,           $this->id, true, $this );
     193                /**
     194                 * Filters the data's user ID before saving to the database.
     195                 *
     196                 * @since 1.0.0
     197                 *
     198                 * @param int $user_id The user ID.
     199                 * @param int $data_id The field data ID.
     200                 */
     201                $this->user_id = apply_filters( 'xprofile_data_user_id_before_save', $this->user_id, $this->id );
     202
     203                /**
     204                 * Filters the data's field ID before saving to the database.
     205                 *
     206                 * @since 1.0.0
     207                 *
     208                 * @param int $field_id The field ID.
     209                 * @param int $data_id  The field data ID.
     210                 */
     211                $this->field_id = apply_filters( 'xprofile_data_field_id_before_save', $this->field_id, $this->id );
     212
     213                /**
     214                 * Filters the data's value before saving to the database.
     215                 *
     216                 * @since 1.0.0
     217                 *
     218                 * @param string                  $field_value The field value.
     219                 * @param int                     $data_id     The field data ID.
     220                 * @param bool                    $reserialize Whether to reserialize the array before returning. Defaults to true.
     221                 * @param BP_XProfile_ProfileData $data_obj    The current field data object.
     222                 */
     223                $this->value = apply_filters( 'xprofile_data_value_before_save', $this->value, $this->id, true, $this );
     224
     225                /**
     226                 * Filters the data's last updated timestamp before saving to the database.
     227                 *
     228                 * @since 1.0.0
     229                 *
     230                 * @param int $last_updated The last updated timestamp.
     231                 * @param int $data_id      The field data ID.
     232                 */
    190233                $this->last_updated = apply_filters( 'xprofile_data_last_updated_before_save', bp_core_current_time(), $this->id );
    191234
    192235                /**
    class BP_XProfile_ProfileData { 
    201244                do_action_ref_array( 'xprofile_data_before_save', array( $this ) );
    202245
    203246                if ( $this->is_valid_field() ) {
    204                         if ( $this->exists() && strlen( trim( $this->value ) ) ) {
     247
     248                        // Store as multiple values
     249                        if ( $this->exists() && ! empty( $this->value ) && bp_xprofile_field_supports_multiple_values( $this->field_id ) ) {
     250
     251                                // Delete previous rows.
     252                                $this->delete();
     253
     254                                // Store each value in a separate row
     255                                foreach ( array_values( (array) $this->value ) as $k => $value ) {
     256                                        $result = $wpdb->query( $wpdb->prepare("INSERT INTO {$bp->profile->table_name_data} (user_id, field_id, value, last_updated) VALUES (%d, %d, %s, %s)", $this->user_id, $this->field_id, $value, $this->last_updated ) );
     257
     258                                        // Use the first inserted id as the new data identifier
     259                                        if ( 0 === $k ) {
     260                                                $this->id = $wpdb->insert_id;
     261                                        }
     262                                }
     263
     264                        // Store as single value
     265                        } elseif ( $this->exists() && strlen( trim( $value ) ) ) {
    205266                                $result   = $wpdb->query( $wpdb->prepare( "UPDATE {$bp->profile->table_name_data} SET value = %s, last_updated = %s WHERE user_id = %d AND field_id = %d", $this->value, $this->last_updated, $this->user_id, $this->field_id ) );
    206267
    207268                        } elseif ( $this->exists() && empty( $this->value ) ) {
    class BP_XProfile_ProfileData { 
    299360                        // Rekey.
    300361                        $queried_data = array();
    301362                        foreach ( $uncached_data as $ud ) {
    302                                 $d               = new stdClass;
    303                                 $d->id           = $ud->id;
    304                                 $d->user_id      = $ud->user_id;
    305                                 $d->field_id     = $ud->field_id;
    306                                 $d->value        = $ud->value;
    307                                 $d->last_updated = $ud->last_updated;
    308 
    309                                 $queried_data[ $ud->field_id ] = $d;
     363
     364                                // Set initial field data
     365                                if ( ! isset( $queried_data[ $ud->field_id ] ) ) {
     366                                        $d               = new stdClass;
     367                                        $d->id           = $ud->id;
     368                                        $d->user_id      = $ud->user_id;
     369                                        $d->field_id     = $ud->field_id;
     370                                        $d->last_updated = $ud->last_updated;
     371
     372                                        // Collect multiple values in array
     373                                        // TODO: no stripslashing here? See ::populate()
     374                                        if ( bp_xprofile_field_supports_multiple_values( $ud->field_id ) ) {
     375                                                $d->value    = array( $ud->value );
     376                                        } else {
     377                                                $d->value    = $ud->value;
     378                                        }
     379
     380                                        $queried_data[ $ud->field_id ] = $d;
     381
     382                                // Collect multiple values per field
     383                                } elseif ( bp_xprofile_field_supports_multiple_values( $ud->field_id ) ) {
     384                                        // TODO: no stripslashing here? See ::populate()
     385                                        $queried_data[ $ud->field_id ]->value[] = $ud->value;
     386                                }
    310387                        }
    311388
    312389                        // Set caches.
    class BP_XProfile_ProfileData { 
    325402                                        $d->id           = '';
    326403                                        $d->user_id      = $user_id;
    327404                                        $d->field_id     = $field_id;
    328                                         $d->value        = '';
     405                                        $d->value        = bp_xprofile_field_supports_multiple_values( $field_id ) ? array() : '';
    329406                                        $d->last_updated = '';
    330407
    331408                                        wp_cache_set( $cache_key, $d, 'bp_xprofile_data' );
    class BP_XProfile_ProfileData { 
    405482         * Get the user's field data id by the id of the xprofile field.
    406483         *
    407484         * @since 1.6.0
     485         * @since 2.9.0 Returns the first/main data id in case of multiple values.
    408486         *
    409487         * @param int $field_id Field ID being queried for.
    410488         * @param int $user_id  User ID associated with field.
    class BP_XProfile_ProfileData { 
    471549                        $bp = buddypress();
    472550                        $uncached_ids_sql = implode( ',', $uncached_ids );
    473551                        $queried_data = $wpdb->get_results( $wpdb->prepare( "SELECT id, user_id, field_id, value, last_updated FROM {$bp->profile->table_name_data} WHERE field_id = %d AND user_id IN ({$uncached_ids_sql})", $field_id ) );
     552                        $multiple = bp_xprofile_field_supports_multiple_values( $field_id );
    474553
    475554                        // Rekey.
    476555                        $qd = array();
    477556                        foreach ( $queried_data as $data ) {
    478                                 $qd[ $data->user_id ] = $data;
     557
     558                                // Set initial user data
     559                                if ( ! isset( $qd[ $data->user_id ] ) ) {
     560
     561                                        // Collect multiple values in array
     562                                        if ( $multiple ) {
     563                                                // TODO: no stripslashing here? See ::populate().
     564                                                $data->value = array( $data->value );
     565                                        }
     566
     567                                        $qd[ $data->user_id ] = $data;
     568
     569                                // Collect multiple values per field
     570                                } elseif ( $multiple ) {
     571                                        // TODO: no stripslashing here? See ::populate().
     572                                        $qd[ $data->user_id ]->value[] = $data->value;
     573                                }
    479574                        }
    480575
    481576                        foreach ( $uncached_ids as $id ) {
    class BP_XProfile_ProfileData { 
    490585                                        $d->id           = '';
    491586                                        $d->user_id      = $id;
    492587                                        $d->field_id     = $field_id;
    493                                         $d->value        = '';
     588                                        $d->value        = $multiple ? array() : '';
    494589                                        $d->last_updated = '';
    495590                                }
    496591
    class BP_XProfile_ProfileData { 
    566661                        $field_sql .= $wpdb->prepare( "AND f.name = %s", $fields );
    567662                }
    568663
    569                 $sql    = $wpdb->prepare( "SELECT d.value, f.name FROM {$bp->profile->table_name_data} d, {$bp->profile->table_name_fields} f WHERE d.field_id = f.id AND d.user_id = %d AND f.parent_id = 0 $field_sql", $user_id );
     664                $sql    = $wpdb->prepare( "SELECT d.value, f.name, f.id FROM {$bp->profile->table_name_data} d, {$bp->profile->table_name_fields} f WHERE d.field_id = f.id AND d.user_id = %d AND f.parent_id = 0 $field_sql", $user_id );
    570665                $values = $wpdb->get_results( $sql );
    571666
     667                // TODO: checking for empty result/WP_Error, but not in other methods?
    572668                if ( empty( $values ) || is_wp_error( $values ) ) {
    573669                        return false;
    574670                }
    class BP_XProfile_ProfileData { 
    579675                        for ( $i = 0, $count = count( $values ); $i < $count; ++$i ) {
    580676                                for ( $j = 0; $j < count( $fields ); $j++ ) {
    581677                                        if ( $values[$i]->name == $fields[$j] ) {
    582                                                 $new_values[$fields[$j]] = $values[$i]->value;
     678                                                $multiple = bp_xprofile_field_supports_multiple_values( $values[$i]->id );
     679
     680                                                // TODO: no stripslashing here? See ::populate()
     681                                                if ( ! isset( $new_values[ $fields[$j] ] ) ) {
     682                                                        $new_values[$fields[$j]] = $multiple ? array( $values[$i]->value ) : $values[$i]->value;
     683                                                } elseif ( $multiple ) {
     684                                                        $new_values[$fields[$j]][] = $values[$i]->value;
     685                                                }
    583686                                        } elseif ( !array_key_exists( $fields[$j], $new_values ) ) {
    584687                                                $new_values[$fields[$j]] = NULL;
    585688                                        }
    586689                                }
    587690                        }
    588691                } else {
    589                         $new_values = $values[0]->value;
     692
     693                        // Collect multiple values in array
     694                        // TODO: no stripslashing here? See ::populate()
     695                        if ( bp_xprofile_field_supports_multiple_values( $values[0]->id ) ) {
     696                                $new_values = wp_list_pluck( $values, 'value' );
     697                        } else {
     698                                $new_values = $values[0]->value;
     699                        }
    590700                }
    591701
    592702                return $new_values;
    class BP_XProfile_ProfileData { 
    651761         *
    652762         * @since 1.0.0
    653763         *
    654          * @param int    $user_id          User ID to query for.
    655          * @param string $exclude_fullname SQL portion used to exclude by field ID.
     764         * @param int  $user_id          User ID to query for.
     765         * @param bool $exclude_fullname Optional. Whether to exclude the fullname field. Defaults to false.
    656766         * @return array|null|object
    657767         */
    658         public static function get_random( $user_id, $exclude_fullname ) {
     768        public static function get_random( $user_id, $exclude_fullname = false ) {
    659769                global $wpdb;
    660770
    661771                $exclude_sql = ! empty( $exclude_fullname ) ? ' AND pf.id != 1' : '';
    662772
    663773                $bp = buddypress();
    664774
    665                 return $wpdb->get_results( $wpdb->prepare( "SELECT pf.type, pf.name, pd.value FROM {$bp->profile->table_name_data} pd INNER JOIN {$bp->profile->table_name_fields} pf ON pd.field_id = pf.id AND pd.user_id = %d {$exclude_sql} ORDER BY RAND() LIMIT 1", $user_id ) );
     775                $rand_sql = "SELECT id FROM {$bp->profile->table_name_fields} ORDER BY RAND() LIMIT 1";
     776                $result   = $wpdb->get_results( $wpdb->prepare( "SELECT pf.type, pf.name, pd.value, pf.id FROM {$bp->profile->table_name_data} pd INNER JOIN {$bp->profile->table_name_fields} pf ON pd.field_id = pf.id AND pd.user_id = %d {$exclude_sql} WHERE pf.id IN ($rand_sql)", $user_id ) );
     777
     778                // Collect multiple values in array
     779                if ( bp_xprofile_field_supports_multiple_values( $result[0]->id ) ) {
     780                        // TODO: no stripslashing here? See ::populate()
     781                        $result->value = wp_list_pluck( $result, 'value' );
     782                        $result = $result[0];
     783                }
     784
     785                return $result;
    666786        }
    667787
    668788        /**