Skip to:
Content

BuddyPress.org

Ticket #6347: 6347.03.patch

File 6347.03.patch, 42.6 KB (added by johnjamesjacoby, 5 years ago)

First pass at refactoring BP_XProfile_Field

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

     
    449449        // Check the nonce
    450450        check_admin_referer( 'bp_reorder_fields', '_wpnonce_reorder_fields' );
    451451
    452         if ( empty( $_POST['field_order'] ) ) {
     452        // Bail if missing POST data
     453        if ( empty( $_POST['field_order'] ) || empty( $_POST['field_group_id'] ) ) {
    453454                return false;
    454455        }
    455456
    456457        parse_str( $_POST['field_order'], $order );
    457458
    458         $field_group_id = $_POST['field_group_id'];
    459 
    460459        foreach ( (array) $order['field'] as $position => $field_id ) {
    461                 xprofile_update_field_position( (int) $field_id, (int) $position, (int) $field_group_id );
     460                xprofile_update_field_position( (int) $field_id, (int) $position, (int) $_POST['field_group_id'] );
    462461        }
    463462}
    464463add_action( 'wp_ajax_xprofile_reorder_fields', 'xprofile_ajax_reorder_fields' );
  • src/bp-xprofile/bp-xprofile-functions.php

     
    968968}
    969969
    970970/**
     971 * Get array of field IDs to show on member registration page
     972 *
     973 * @since BuddyPress (2.3.0)
     974 *
     975 * @global $wpdb $wpdb
     976 * @return array
     977 */
     978function bp_xprofile_get_signup_field_ids() {
     979        global $wpdb;
     980
     981        $field_ids = array();
     982        $fields    = wp_cache_get( 'signup_fields', 'bp_xprofile' );
     983        if ( false === $fields ) {
     984                $table_key  = 'xprofile_fieldmeta';
     985                $table_name = $wpdb->{$table_key};
     986                $sql        = $wpdb->prepare( "SELECT * FROM {$table_name} WHERE object_type = %s AND meta_key = %s", 'field', 'signup_position' );
     987                $fields     = $wpdb->get_results( $sql );
     988
     989                wp_cache_set( 'signup_fields', $fields, 'bp_xprofile' );
     990        }
     991
     992        // Bail if no signup fields
     993        if ( ! empty( $fields ) ) {
     994                $field_ids = wp_list_pluck( $fields, 'object_id' );
     995        }
     996
     997        return apply_filters( 'bp_xprofile_get_signup_field_ids', $field_ids, $fields );
     998}
     999
     1000/**
    9711001 * Return the field ID for the Full Name xprofile field.
    9721002 *
    9731003 * @since BuddyPress (2.0.0)
  • src/bp-xprofile/bp-xprofile-loader.php

     
    367367                wp_cache_add_global_groups( array(
    368368                        'bp_xprofile',
    369369                        'bp_xprofile_data',
     370                        'bp_xprofile_fields',
    370371                        'bp_xprofile_groups',
    371372                        'xprofile_meta'
    372373                ) );
  • src/bp-xprofile/classes/class-bp-xprofile-field.php

     
    110110        public $allow_custom_visibility = 'allowed';
    111111
    112112        /**
     113         * @since BuddyPress (2.3.0)
     114         *
     115         * @var int Position of field on user registration page
     116         */
     117        public $signup_position = null;
     118
     119        /**
    113120         * @since BuddyPress (2.0.0)
    114121         *
    115122         * @var BP_XProfile_Field_Type Field type object used for validation
     
    157164         * @param  bool   $get_data
    158165         */
    159166        public function populate( $id, $user_id = null, $get_data = true ) {
    160                 global $wpdb, $userdata;
    161167
    162                 if ( empty( $user_id ) ) {
    163                         $user_id = isset( $userdata->ID ) ? $userdata->ID : 0;
    164                 }
     168                // Check for cached field
     169                $field = wp_cache_get( $id, 'bp_xprofile_fields' );
    165170
    166                 $bp    = buddypress();
    167                 $field = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$bp->profile->table_name_fields} WHERE id = %d", $id ) );
     171                // Field not cached, so query (and subsequently cache)
     172                if ( false === $field ) {
    168173
    169                 if ( ! empty( $field ) ) {
    170                         $this->id                = $field->id;
    171                         $this->group_id          = $field->group_id;
    172                         $this->parent_id         = $field->parent_id;
    173                         $this->type              = $field->type;
    174                         $this->name              = stripslashes( $field->name );
    175                         $this->description       = stripslashes( $field->description );
    176                         $this->is_required       = $field->is_required;
    177                         $this->can_delete        = $field->can_delete;
    178                         $this->field_order       = $field->field_order;
    179                         $this->option_order      = $field->option_order;
    180                         $this->order_by          = $field->order_by;
    181                         $this->is_default_option = $field->is_default_option;
     174                        // Setup args
     175                        $args = array(
     176                                'include' => $id
     177                        );
    182178
    183                         // Create the field type and store a reference back to this object.
    184                         $this->type_obj            = bp_xprofile_create_field_type( $field->type );
    185                         $this->type_obj->field_obj = $this;
    186 
    187                         if ( ! empty( $get_data ) && ! empty( $user_id ) ) {
    188                                 $this->data = $this->get_field_data( $user_id );
     179                        // Get data for the user ID
     180                        if ( ! empty( $user_id ) && ! empty( $get_data ) ) {
     181                                $args['fetch_data'] = $user_id;
    189182                        }
    190183
    191                         // Get metadata for field
    192                         $default_visibility       = bp_xprofile_get_meta( $id, 'field', 'default_visibility'      );
    193                         $allow_custom_visibility  = bp_xprofile_get_meta( $id, 'field', 'allow_custom_visibility' );
     184                        // Get the field and its data
     185                        $field = self::get( $args );
    194186
    195                         // Setup default visibility
    196                         $this->default_visibility = ! empty( $default_visibility )
    197                                 ? $default_visibility
    198                                 : 'public';
     187                        // Use the first item if an array
     188                        if ( array( $field ) ) {
     189                                $field = reset( $field );
     190                        }
     191                }
    199192
    200                         // Allow members to customize visibilty
    201                         $this->allow_custom_visibility = ( 'disabled' === $allow_custom_visibility )
    202                                 ? 'disabled'
    203                                 : 'allowed';
     193                // Bail if field could not be found
     194                if ( empty( $field ) ) {
     195                        return;
    204196                }
    205         }
    206197
    207         /**
    208          * Delete a profile field
    209          *
    210          * @since BuddyPress (1.1.0)
    211          *
    212          * @global object  $wpdb
    213          * @param  boolean $delete_data
    214          * @return boolean
    215          */
    216         public function delete( $delete_data = false ) {
    217                 global $wpdb;
     198                // Setup this field
     199                $this->id                = $field->id;
     200                $this->group_id          = $field->group_id;
     201                $this->parent_id         = $field->parent_id;
     202                $this->type              = $field->type;
     203                $this->name              = stripslashes( $field->name );
     204                $this->description       = stripslashes( $field->description );
     205                $this->is_required       = $field->is_required;
     206                $this->is_default_option = $field->is_default_option;
     207                $this->field_order       = $field->field_order;
     208                $this->option_order      = $field->option_order;
     209                $this->order_by          = $field->order_by;
     210                $this->can_delete        = $field->can_delete;
    218211
    219                 // Prevent deletion if no ID is present
    220                 // Prevent deletion by url when can_delete is false.
    221                 // Prevent deletion of option 1 since this invalidates fields with options.
    222                 if ( empty( $this->id ) || empty( $this->can_delete ) || ( $this->parent_id && $this->option_order == 1 ) ) {
    223                         return false;
     212                // Set field data if it was requested
     213                if ( ! empty( $field->data ) ) {
     214                        $this->data = $field->data;
    224215                }
    225216
    226                 $bp  = buddypress();
    227                 $sql = $wpdb->prepare( "DELETE FROM {$bp->profile->table_name_fields} WHERE id = %d OR parent_id = %d", $this->id, $this->id );
     217                // Create the field type and store a reference back to this object.
     218                $this->type_obj            = bp_xprofile_create_field_type( $field->type );
     219                $this->type_obj->field_obj = $this;
    228220
    229                 if ( ! $wpdb->query( $sql ) ) {
    230                         return false;
    231                 }
     221                // Get core metadata for field
     222                $default_visibility      = bp_xprofile_get_meta( $id, 'field', 'default_visibility'      );
     223                $allow_custom_visibility = bp_xprofile_get_meta( $id, 'field', 'allow_custom_visibility' );
     224                $signup_position         = bp_xprofile_get_meta( $id, 'field', 'signup_position'         );
    232225
    233                 // delete the data in the DB for this field
    234                 if ( true === $delete_data ) {
    235                         BP_XProfile_ProfileData::delete_for_field( $this->id );
    236                 }
     226                // Setup default visibility
     227                $this->default_visibility = ! empty( $default_visibility )
     228                        ? $default_visibility
     229                        : 'public';
    237230
    238                 return true;
     231                // Allow members to customize visibilty
     232                $this->allow_custom_visibility = ( 'disabled' === $allow_custom_visibility )
     233                        ? 'disabled'
     234                        : 'allowed';
     235
     236                // Is this field used on the registration page
     237                $this->signup_position = ( false !== $signup_position )
     238                        ? $signup_position
     239                        : null;
    239240        }
    240241
    241242        /**
     
    245246         *
    246247         * @global object $wpdb
    247248         *
     249         * @param  boolean $update_children Should child fields be updated?
     250         *
    248251         * @return boolean
    249252         */
    250         public function save() {
     253        public function save( $updating_position = false ) {
    251254                global $wpdb;
    252255
    253256                $bp = buddypress();
    254257
    255                 $this->group_id     = apply_filters( 'xprofile_field_group_id_before_save',     $this->group_id,     $this->id );
    256                 $this->parent_id    = apply_filters( 'xprofile_field_parent_id_before_save',    $this->parent_id,    $this->id );
    257                 $this->type         = apply_filters( 'xprofile_field_type_before_save',         $this->type,         $this->id );
    258                 $this->name         = apply_filters( 'xprofile_field_name_before_save',         $this->name,         $this->id );
    259                 $this->description  = apply_filters( 'xprofile_field_description_before_save',  $this->description,  $this->id );
    260                 $this->is_required  = apply_filters( 'xprofile_field_is_required_before_save',  $this->is_required,  $this->id );
    261                 $this->order_by     = apply_filters( 'xprofile_field_order_by_before_save',     $this->order_by,     $this->id );
    262                 $this->field_order  = apply_filters( 'xprofile_field_field_order_before_save',  $this->field_order,  $this->id );
    263                 $this->option_order = apply_filters( 'xprofile_field_option_order_before_save', $this->option_order, $this->id );
    264                 $this->can_delete   = apply_filters( 'xprofile_field_can_delete_before_save',   $this->can_delete,   $this->id );
    265                 $this->type_obj     = bp_xprofile_create_field_type( $this->type );
     258                $this->group_id            = apply_filters( 'xprofile_field_group_id_before_save',          $this->group_id,          $this->id );
     259                $this->parent_id           = apply_filters( 'xprofile_field_parent_id_before_save',         $this->parent_id,         $this->id );
     260                $this->type                = apply_filters( 'xprofile_field_type_before_save',              $this->type,              $this->id );
     261                $this->name                = apply_filters( 'xprofile_field_name_before_save',              $this->name,              $this->id );
     262                $this->description         = apply_filters( 'xprofile_field_description_before_save',       $this->description,       $this->id );
     263                $this->is_required         = apply_filters( 'xprofile_field_is_required_before_save',       $this->is_required,       $this->id );
     264                $this->is_default_option   = apply_filters( 'xprofile_field_is_default_option_before_save', $this->is_default_option, $this->id );
     265                $this->field_order         = apply_filters( 'xprofile_field_field_order_before_save',       $this->field_order,       $this->id );
     266                $this->option_order        = apply_filters( 'xprofile_field_option_order_before_save',      $this->option_order,      $this->id );
     267                $this->order_by            = apply_filters( 'xprofile_field_order_by_before_save',          $this->order_by,          $this->id );
     268                $this->can_delete          = apply_filters( 'xprofile_field_can_delete_before_save',        $this->can_delete,        $this->id );
     269                $this->type_obj            = bp_xprofile_create_field_type( $this->type );
     270                $this->type_obj->field_obj = $this;
    266271
    267272                /**
    268273                 * Fires before the current field instance gets saved.
     
    275280                 */
    276281                do_action_ref_array( 'xprofile_field_before_save', array( $this ) );
    277282
    278                 if ( $this->id != null ) {
    279                         $sql = $wpdb->prepare( "UPDATE {$bp->profile->table_name_fields} SET group_id = %d, parent_id = 0, type = %s, name = %s, description = %s, is_required = %d, order_by = %s, field_order = %d, option_order = %d, can_delete = %d WHERE id = %d", $this->group_id, $this->type, $this->name, $this->description, $this->is_required, $this->order_by, $this->field_order, $this->option_order, $this->can_delete, $this->id );
     283                // Existing field
     284                if ( ! empty( $this->id ) ) {
     285                        $sql = $wpdb->prepare( "UPDATE {$bp->profile->table_name_fields} SET group_id = %d, parent_id = %d, type = %s, name = %s, description = %s, is_required = %d, is_default_option = %d, order_by = %s, field_order = %d, option_order = %d, can_delete = %d WHERE id = %d", $this->group_id, $this->parent_id, $this->type, $this->name, $this->description, $this->is_required, $this->is_default_option, $this->order_by, $this->field_order, $this->option_order, $this->can_delete, $this->id );
     286
     287                // New field
    280288                } else {
    281                         $sql = $wpdb->prepare( "INSERT INTO {$bp->profile->table_name_fields} (group_id, parent_id, type, name, description, is_required, order_by, field_order, option_order, can_delete ) VALUES (%d, %d, %s, %s, %s, %d, %s, %d, %d, %d )", $this->group_id, $this->parent_id, $this->type, $this->name, $this->description, $this->is_required, $this->order_by, $this->field_order, $this->option_order, $this->can_delete );
     289                        $sql = $wpdb->prepare( "INSERT INTO {$bp->profile->table_name_fields} (group_id, parent_id, type, name, description, is_required, is_default_option, order_by, field_order, option_order, can_delete ) VALUES (%d, %d, %s, %s, %s, %d, %d, %s, %d, %d, %d )",             $this->group_id, $this->parent_id, $this->type, $this->name, $this->description, $this->is_required, $this->is_default_option, $this->order_by, $this->field_order, $this->option_order, $this->can_delete );
    282290                }
    283291
     292                // Attempt to update or insert
     293                $query = $wpdb->query( $sql );
     294
    284295                /**
    285                  * Check for null so field options can be changed without changing any
    286                  * other part of the field. The described situation will return 0 here.
     296                 * Check for `null` instead of `false` or `empty()` to allow child
     297                 * field-options to be modified even if no other field properties changed.
    287298                 */
    288                 if ( $wpdb->query( $sql ) !== null ) {
     299                if ( ( null === $query ) || is_wp_error( $query ) ) {
     300                        return false;
     301                }
    289302
    290                         if ( !empty( $this->id ) ) {
    291                                 $field_id = $this->id;
    292                         } else {
    293                                 $field_id = $wpdb->insert_id;
    294                         }
     303                // Update existing field
     304                if ( empty( $this->id ) ) {
     305                        $this->id = $wpdb->insert_id;
     306                }
    295307
    296                         // Only do this if we are editing an existing field
    297                         if ( $this->id != null ) {
     308                // Delete the relevant caches
     309                $this->purge_caches();
    298310
    299                                 /**
    300                                  * Remove any radio or dropdown options for this
    301                                  * field. They will be re-added if needed.
    302                                  * This stops orphan options if the user changes a
    303                                  * field from a radio button field to a text box.
    304                                  */
    305                                 $this->delete_children();
    306                         }
     311                /**
     312                 * Check to see if this is a field with child options.
     313                 * We need to add the options to the db, if it is.
     314                 */
     315                if ( ( false === $updating_position ) && ! empty( $this->type_obj->supports_options ) ) {
    307316
    308317                        /**
    309                          * Check to see if this is a field with child options.
    310                          * We need to add the options to the db, if it is.
     318                         * Remove any field-options for this field. They will be re-added if
     319                         * needed. This prenets orphaned options if the user changes a field
     320                         * from a radio-button with options to a textbox without.
     321                         *
     322                         * It's maybe a bit of a brute-force approach, but seems easier than
     323                         * querying for items & updating/deleting/creating each time;
     324                         * and 60% of the time, it works everytime, so that's nice.
    311325                         */
    312                         if ( $this->type_obj->supports_options ) {
     326                        $this->delete_children();
    313327
    314                                 if ( !empty( $this->id ) ) {
    315                                         $parent_id = $this->id;
    316                                 } else {
    317                                         $parent_id = $wpdb->insert_id;
    318                                 }
     328                        // Allow plugins to filter the field's child options (i.e. the items in a selectbox).
     329                        $post_options  = ! empty( $_POST["{$this->type}_option"]           ) ? $_POST["{$this->type}_option"]           : '';
     330                        $post_defaults = ! empty( $_POST["isDefault_{$this->type}_option"] ) ? $_POST["isDefault_{$this->type}_option"] : '';
    319331
    320                                 // Allow plugins to filter the field's child options (i.e. the items in a selectbox).
    321                                 $post_option  = ! empty( $_POST["{$this->type}_option"]           ) ? $_POST["{$this->type}_option"]           : '';
    322                                 $post_default = ! empty( $_POST["isDefault_{$this->type}_option"] ) ? $_POST["isDefault_{$this->type}_option"] : '';
     332                        /**
     333                         * Filters the submitted field option value before saved.
     334                         *
     335                         * @since BuddyPress (1.5.0)
     336                         *
     337                         * @param string            $post_options Submitted option value.
     338                         * @param BP_XProfile_Field $type         Current field type being saved for.
     339                         */
     340                        $options = apply_filters( 'xprofile_field_options_before_save', $post_options,  $this->type );
    323341
    324                                 /**
    325                                  * Filters the submitted field option value before saved.
    326                                 *
    327                                 * @since BuddyPress (1.5.0)
    328                                 *
    329                                  * @param string            $post_option Submitted option value.
    330                                  * @param BP_XProfile_Field $type        Current field type being saved for.
    331                                 */
    332                                 $options      = apply_filters( 'xprofile_field_options_before_save', $post_option, $this->type );
     342                        /**
     343                         * Filters the default field option value before saved.
     344                        *
     345                        * @since BuddyPress (1.5.0)
     346                        *
     347                         * @param string            $post_defaults Default option value.
     348                         * @param BP_XProfile_Field $type          Current field type being saved for.
     349                        */
     350                        $defaults = apply_filters( 'xprofile_field_default_before_save', $post_defaults, $this->type );
    333351
    334                                 /**
    335                                  * Filters the default field option value before saved.
    336                                  *
    337                                  * @since BuddyPress (1.5.0)
    338                                  *
    339                                  * @param string            $post_default Default option value.
    340                                  * @param BP_XProfile_Field $type         Current field type being saved for.
    341                                  */
    342                                 $defaults     = apply_filters( 'xprofile_field_default_before_save', $post_default, $this->type );
     352                        // There are options that need recreating
     353                        if ( ! empty( $options ) ) {
    343354
     355                                // Start counter at 1 to avoid 0 values
    344356                                $counter = 1;
    345                                 if ( !empty( $options ) ) {
    346                                         foreach ( (array) $options as $option_key => $option_value ) {
    347                                                 $is_default = 0;
    348357
    349                                                 if ( is_array( $defaults ) ) {
    350                                                         if ( isset( $defaults[ $option_key ] ) ) {
    351                                                                 $is_default = 1;
    352                                                         }
    353                                                 } else {
    354                                                         if ( (int) $defaults == $option_key ) {
    355                                                                 $is_default = 1;
    356                                                         }
    357                                                 }
     358                                // Loop through options and re-create them
     359                                foreach ( (array) $options as $option_key => $option_name ) {
    358360
    359                                                 if ( '' != $option_value ) {
    360                                                         $sql = $wpdb->prepare( "INSERT INTO {$bp->profile->table_name_fields} (group_id, parent_id, type, name, description, is_required, option_order, is_default_option) VALUES (%d, %d, 'option', %s, '', 0, %d, %d)", $this->group_id, $parent_id, $option_value, $counter, $is_default );
    361                                                         if ( ! $wpdb->query( $sql ) ) {
    362                                                                 return false;
    363                                                         }
    364                                                 }
     361                                        // Determine if option is the default
     362                                        if ( is_array( $defaults ) && isset( $defaults[ $option_key ] ) ) {
     363                                                $is_default = 1;
     364                                        } elseif ( (int) $defaults == $option_key ) {
     365                                                $is_default = 1;
     366                                        } else {
     367                                                $is_default = 0;
     368                                        }
    365369
    366                                                 $counter++;
     370                                        // Recreate the option based on value and other criteria
     371                                        if ( ! empty( $option_name ) ) {
     372                                                $option                    = new BP_XProfile_Field();
     373                                                $option->group_id          = $this->group_id;
     374                                                $option->parent_id         = $this->id;
     375                                                $option->type              = 'option';
     376                                                $option->name              = $option_name;
     377                                                $option->description       = '';
     378                                                $option->is_required       = 0;
     379                                                $option->is_default_option = $is_default;
     380                                                $option->option_order      = $counter;
     381                                                $option->save();
    367382                                        }
     383
     384                                        $counter++;
    368385                                }
    369386                        }
     387                }
    370388
    371                         /**
    372                         * Fires after the current field instance gets saved.
    373                         *
    374                         * @since BuddyPress (1.0.0)
    375                         *
    376                         * @param BP_XProfile_Field Current instance of the field being saved.
    377                         */
    378                         do_action_ref_array( 'xprofile_field_after_save', array( $this ) );
     389                /**
     390                * Fires after the current field instance gets saved.
     391                *
     392                * @since BuddyPress (1.0.0)
     393                *
     394                * @param BP_XProfile_Field Current instance of the field being saved.
     395                */
     396                do_action_ref_array( 'xprofile_field_after_save', array( $this ) );
    379397
    380                         // Recreate type_obj in case someone changed $this->type via a filter
    381                         $this->type_obj            = bp_xprofile_create_field_type( $this->type );
    382                         $this->type_obj->field_obj = $this;
    383 
    384                         return $field_id;
    385                 } else {
    386                         return false;
    387                 }
     398                return (int) $this->id;
    388399        }
    389400
    390401        /**
     
    404415         *
    405416         * @since BuddyPress (1.2.0)
    406417         *
    407          * @global object $wpdb
    408          *
    409418         * @param  bool  $for_editing
    410419         * @return array
    411420         */
    412421        public function get_children( $for_editing = false ) {
    413                 global $wpdb;
    414422
    415423                // This is done here so we don't have problems with sql injection
    416                 if ( empty( $for_editing ) && ( 'asc' === $this->order_by ) ) {
    417                         $sort_sql = 'ORDER BY name ASC';
    418                 } elseif ( empty( $for_editing ) && ( 'desc' === $this->order_by ) ) {
    419                         $sort_sql = 'ORDER BY name DESC';
     424                if ( ( false === $for_editing ) && in_array( strtoupper( $this->order_by ), array( 'ASC', 'DESC' ) ) ) {
     425                        $order_by = 'name';
     426                        $sort     = strtoupper( $this->order_by );
    420427                } else {
    421                         $sort_sql = 'ORDER BY option_order ASC';
     428                        $order_by = 'option_order';
     429                        $sort     = 'ASC';
    422430                }
    423431
    424                 // This eliminates a problem with getting all fields when there is no
    425                 // id for the object
    426                 if ( empty( $this->id ) ) {
    427                         $parent_id = -1;
    428                 } else {
    429                         $parent_id = $this->id;
     432                // Get children
     433                $children = self::get( array(
     434                        'parent_id'         => $this->id,
     435                        'order_by'          => $order_by,
     436                        'sort'              => $sort,
     437                        'update_meta_cache' => false
     438                ) );
     439
     440                // Set children to false if empty or invalid
     441                if ( empty( $children ) || ! is_array( $children ) ) {
     442                        $children = false;
    430443                }
    431444
    432                 $bp  = buddypress();
    433                 $sql = $wpdb->prepare( "SELECT * FROM {$bp->profile->table_name_fields} WHERE parent_id = %d AND group_id = %d {$sort_sql}", $parent_id, $this->group_id );
    434 
    435                 $children = $wpdb->get_results( $sql );
    436 
    437445                /**
    438446                 * Filters the found children for a field.
    439447                 *
     
    446454        }
    447455
    448456        /**
     457         * Delete a profile field
     458         *
     459         * @since BuddyPress (1.1.0)
     460         *
     461         * @global object  $wpdb
     462         * @param  boolean $delete_data
     463         * @param  boolean $delete_children
     464         * @return boolean
     465         */
     466        public function delete( $delete_data = false, $delete_children = true ) {
     467                global $wpdb;
     468
     469                // Prevent deletion if no ID is present
     470                // Prevent deletion by url when can_delete is false.
     471                if ( empty( $this->id ) || empty( $this->can_delete ) ) {
     472                        return false;
     473                }
     474
     475                $bp = buddypress();
     476
     477                // Attempt to get fields to delete
     478                $sql      = $wpdb->prepare( "SELECT id FROM {$bp->profile->table_name_fields} WHERE id = %d LIMIT 1", $this->id );
     479                $field_id = $wpdb->get_var( $sql );
     480
     481                // Bail if no children exist
     482                if ( empty( $field_id ) || is_wp_error( $field_id ) ) {
     483                        return false;
     484                }
     485
     486                // Attempt to delete
     487                $sql     = $wpdb->prepare( "DELETE FROM {$bp->profile->table_name_fields} WHERE id = %d LIMIT 1", $this->id );
     488                $deleted = $wpdb->query( $sql );
     489
     490                // Bail if no children exist
     491                if ( empty( $deleted ) || is_wp_error( $deleted ) ) {
     492                        return false;
     493                }
     494
     495                // Delete cache
     496                // Delete the relevant caches
     497                $this->purge_caches();
     498
     499                // Maybe delete children
     500                if ( true === $delete_children ) {
     501                        $this->delete_children();
     502                }
     503
     504                // delete the data in the DB for this field
     505                if ( true === $delete_data ) {
     506                        BP_XProfile_ProfileData::delete_for_field( $this->id );
     507                }
     508
     509                return true;
     510        }
     511
     512        /**
    449513         * Delete all field children for this field
    450514         *
    451515         * @since BuddyPress (1.2.0)
     
    455519        public function delete_children() {
    456520                global $wpdb;
    457521
    458                 $bp  = buddypress();
    459                 $sql = $wpdb->prepare( "DELETE FROM {$bp->profile->table_name_fields} WHERE parent_id = %d", $this->id );
     522                $bp = buddypress();
    460523
    461                 $wpdb->query( $sql );
     524                // Attempt to get fields to delete
     525                $sql       = $wpdb->prepare( "SELECT id FROM {$bp->profile->table_name_fields} WHERE parent_id = %d", $this->id );
     526                $field_ids = $wpdb->get_col( $sql );
     527
     528                // Bail if no children exist
     529                if ( empty( $field_ids ) || is_wp_error( $field_ids ) ) {
     530                        return false;
     531                }
     532
     533                // Delete child fields
     534                foreach ( $field_ids as $field_id ) {
     535                        $field = new BP_XProfile_Field( $field_id );
     536                        $field->delete( false, false );
     537                }
     538
     539                // We care less about actual option deletion at this point
     540                return true;
    462541        }
    463542
    464543        /** Static Methods ********************************************************/
    465544
    466         public static function get_type( $field_id = 0 ) {
     545        /**
     546         * Get profile fields, as specified by parameters
     547         *
     548         * @see BP_Activity_Activity::get_filter_sql() for a description of the
     549         *      'filter' parameter.
     550         * @see WP_Meta_Query::queries for a description of the 'meta_query'
     551         *      parameter format.
     552         *
     553         * @param array $args {
     554         *     An array of arguments. All items are optional.
     555         *
     556         *     @type int          $page              Which page of results to fetch. Using page=1 without per_page will result
     557         *                                           in no pagination. Default: 1.
     558         *     @type int|bool     $per_page          Number of results per page. Default: 25.
     559         *     @type int|bool     $max               Maximum number of results to return. Default: false (unlimited).
     560         *     @type string       $sort              ASC or DESC. Default: 'DESC'.
     561         *     @type array        $exclude           Array of activity IDs to exclude. Default: false.
     562         *     @type array        $in                Array of ids to limit query by (IN). Default: false.
     563         *     @type array        $meta_query        Array of meta_query conditions. See WP_Meta_Query::queries.
     564         *     @type array        $date_query        Array of date_query conditions. See first parameter of
     565         *                                           WP_Date_Query::__construct().
     566         *     @type array        $filter_query      Array of advanced query conditions. See BP_Activity_Query::__construct().
     567         *     @type string|array $scope             Pre-determined set of activity arguments.
     568         *     @type array        $filter            See BP_Activity_Activity::get_filter_sql().
     569         *     @type string       $search_terms      Limit results by a search term. Default: false.
     570         *     @type bool         $display_comments  Whether to include activity comments. Default: false.
     571         *     @type bool         $show_hidden       Whether to show items marked hide_sitewide. Default: false.
     572         *     @type string       $spam              Spam status. Default: 'ham_only'.
     573         *     @type bool         $update_meta_cache Whether to pre-fetch metadata for queried activity items. Default: true.
     574         *     @type string|bool  $count_total       If true, an additional DB query is run to count the total activity items
     575         *                                           for the query. Default: false.
     576         * }
     577         * @return array The array returned has two keys:
     578         *     - 'total' is the count of located activities
     579         *     - 'activities' is an array of the located activities
     580         */
     581        public static function get( $args = '' ) {
    467582                global $wpdb;
    468583
     584                $r  = wp_parse_args( $args, array(
     585                        'include'           => false,
     586                        'exclude'           => false,
     587                        'group_id'          => false,
     588                        'group_not_in'      => false,
     589                        'parent_id'         => false,
     590                        'parent_not_in'     => false,
     591                        'type_in'           => false,
     592                        'type_not_in'       => false,
     593                        'name'              => '',
     594                        'is_required'       => false,
     595                        'is_default_option' => false,
     596                        'can_delete'        => 1,
     597                        'order_by'          => false,
     598                        'sort'              => 'ASC',
     599                        'fetch_data'        => false,
     600                        'meta_query'        => false, // @todo implement
     601                        'update_meta_cache' => true
     602                ) );
     603
     604                // Get the profile fields table name
     605                $table_name = buddypress()->profile->table_name_fields;
     606
     607                // Select conditions
     608                $select_sql = "SELECT *";
     609
     610                $from_sql   = " FROM {$table_name} f";
     611
     612                $join_sql   = '';
     613
     614                // Where conditions
     615                $where_conditions = array();
     616
     617                /** Field ID **********************************************************/
     618
     619                // Setup IN query for field IDs
     620                if ( ! empty( $r['include'] ) ) {
     621                        $include_in                  = implode( ',', wp_parse_id_list( $r['include'] ) );
     622                        $where_conditions['include'] = "id IN ({$include_in})";
     623                }
     624
     625                // Setup NOT IN query for field IDs
     626                if ( ! empty( $r['exclude'] ) ) {
     627                        $exclude_not_in              = implode( ',', wp_parse_id_list( $r['exclude'] ) );
     628                        $where_conditions['exclude'] = "id NOT IN ({$exclude_not_in})";
     629                }
     630
     631                /** Group ID **********************************************************/
     632
     633                // Setup IN query for field-group IDs
     634                if ( ! empty( $r['group_id'] ) ) {
     635                        $group_in                     = implode( ',', wp_parse_id_list( $r['group_id'] ) );
     636                        $where_conditions['group_in'] = "group_id IN ({$group_in})";
     637                }
     638
     639                // Setup NOT IN query for field-group IDs
     640                if ( ! empty( $r['group_not_in'] ) ) {
     641                        $group_not_in                     = implode( ',', wp_parse_id_list( $r['group_not_in'] ) );
     642                        $where_conditions['group_not_in'] = "group_id NOT IN ({$group_not_in})";
     643                }
     644
     645                /** Parent ID *********************************************************/
     646
     647                // Setup IN query for parent-field IDs
     648                if ( ! empty( $r['parent_id'] ) || ( '0' === $r['parent_id'] ) ) {
     649                        $parent_in                     = implode( ',', wp_parse_id_list( $r['parent_id'] ) );
     650                        $where_conditions['parent_in'] = "parent_id IN ({$parent_in})";
     651                }
     652
     653                // Setup NOT IN query for parent-field IDs
     654                if ( ! empty( $r['parent_not_in'] ) ) {
     655                        $parent_not_in                     = implode( ',', wp_parse_id_list( $r['parent_not_in'] ) );
     656                        $where_conditions['parent_not_in'] = "parent_id NOT IN ({$parent_not_in})";
     657                }
     658
     659                /** Types *************************************************************/
     660
     661                // Setup IN query for type-field IDs
     662                if ( ! empty( $r['type_in'] ) ) {
     663                        $type_in                     = implode( ',', wp_parse_id_list( $r['type_in'] ) );
     664                        $where_conditions['type_in'] = "type IN ({$type_in})";
     665                }
     666
     667                // Setup NOT IN query for type-field IDs
     668                if ( ! empty( $r['type_not_in'] ) ) {
     669                        $type_not_in                     = implode( ',', wp_parse_id_list( $r['type_not_in'] ) );
     670                        $where_conditions['type_not_in'] = "type NOT IN ({$type_not_in})";
     671                }
     672
     673                /** Name **************************************************************/
     674
     675                // Setup IN query for type-field IDs
     676                if ( ! empty( $r['name'] ) ) {
     677                        $where_conditions['name'] = $wpdb->prepare( "name = %s", $r['name'] );
     678                }
     679
     680                /** Other *************************************************************/
     681
     682                // Sorting
     683                $sort = $r['sort'];
     684                if ( ! in_array( $sort, array( 'ASC', 'DESC' ) ) ) {
     685                        $sort = 'ASC';
     686                }
     687
     688                // Ordering
     689                $order_by = 'field_order';
     690                if ( ! empty( $r['order_by'] ) ) {
     691                        $order_by = $r['order_by'];
     692                }
     693
     694                // Process meta_query into SQL
     695//              $meta_query_sql = self::get_meta_query_sql( $r['meta_query'] );
     696//
     697//              if ( ! empty( $meta_query_sql['join'] ) ) {
     698//                      $join_sql .= $meta_query_sql['join'];
     699//              }
     700//
     701//              if ( ! empty( $meta_query_sql['where'] ) ) {
     702//                      $where_conditions[] = $meta_query_sql['where'];
     703//              }
     704
     705                /**
     706                 * Filters the MySQL WHERE conditions for the XProfile field get method.
     707                 *
     708                 * @since BuddyPress (2.3.0)
     709                 *
     710                 * @param array  $where_conditions Current conditions for MySQL WHERE statement.
     711                 * @param array  $r                Parsed arguments passed into method.
     712                 * @param string $select_sql       Current SELECT MySQL statement at point of execution.
     713                 * @param string $from_sql         Current FROM MySQL statement at point of execution.
     714                 * @param string $join_sql         Current INNER JOIN MySQL statement at point of execution.
     715                 */
     716                $where_conditions = apply_filters( 'bp_xprofile_get_where_conditions', $where_conditions, $r, $select_sql, $from_sql, $join_sql );
     717
     718                // Bail if no WHERE conditions
     719                if ( empty( $where_conditions ) ) {
     720                        return array();
     721                }
     722
     723                // Join the where conditions together
     724                $where_sql = 'WHERE ' . join( ' AND ', $where_conditions );
     725
     726                /**
     727                 * Filters the preferred order of indexes for xprofile fields.
     728                 *
     729                 * @since BuddyPress (2.3.0)
     730                 *
     731                 * @param array Array of indexes in preferred order.
     732                 */
     733                $indexes = apply_filters( 'bp_xprofile_preferred_index_order', array( 'group_id', 'parent_id', 'field_order', 'can_delete', 'is_required' ) );
     734
     735                foreach ( $indexes as $key => $index ) {
     736                        if ( false !== strpos( $where_sql, $index ) ) {
     737                                $the_index = $index;
     738                                break; // Take the first one we find
     739                        }
     740                }
     741
     742                if ( ! empty( $the_index ) ) {
     743                        $index_hint_sql = "USE INDEX ({$the_index})";
     744                } else {
     745                        $index_hint_sql = '';
     746                }
     747
     748                // Query first for activity IDs
     749                $field_ids_sql = "{$select_sql} {$from_sql} {$index_hint_sql} {$join_sql} {$where_sql} ORDER BY f.{$order_by} {$sort}";
     750                $fields        = $wpdb->get_results( $field_ids_sql );
     751                $field_ids     = wp_list_pluck( $fields, 'id' );
     752
     753                // Bail if no field IDs
     754                if ( empty( $field_ids ) ) {
     755                        return array();
     756                }
     757
     758                // Get fields from queried IDs
     759                self::update_field_caches( $field_ids );
     760
     761                // Maybe update meta cache
     762                if ( ! empty( $field_ids ) ) {
     763
     764                        // Maybe fetch data for all fields
     765                        if ( ! empty( $r['fetch_data'] ) ) {
     766
     767                                // Wipe out the fields array
     768                                $fields = array();
     769
     770                                // Loop through fields and get data for them
     771                                foreach ( $field_ids as $field_id ) {
     772                                        $field       = new BP_XProfile_Field( $field_id );
     773                                        $field->data = $field->get_field_data( $r['fetch_data'] );
     774                                        $fields[]    = $field;
     775                                }
     776                        }
     777
     778                        // Update caches
     779                        if ( ! empty( $r['update_meta_cache'] ) ) {
     780                                bp_xprofile_update_meta_cache( array( 'field' => $field_ids ) );
     781                        }
     782                }
     783
     784                return $fields;
     785        }
     786
     787        /**
     788         * Convert field IDs to field objects, as expected in template loop.
     789         *
     790         * @since BuddyPress (2.3.0)
     791         *
     792         * @param array $field_ids Array of field IDs.
     793         * @return array
     794         */
     795        protected static function update_field_caches( $field_ids = array() ) {
     796                global $wpdb;
     797
     798                // Bail if no field ID's passed
     799                if ( empty( $field_ids ) ) {
     800                        return array();
     801                }
     802
     803                // Get BuddyPress
     804                $uncached_ids = bp_get_non_cached_ids( $field_ids, 'bp_xprofile_fields' );
     805
     806                // Prime caches as necessary
     807                if ( ! empty( $uncached_ids ) ) {
     808
     809                        // Format the field ID's for use in the query below
     810                        $uncached_ids_sql = implode( ',', wp_parse_id_list( $uncached_ids ) );
     811
     812                        // Fetch data from field table, preserving order
     813                        $table_name    = buddypress()->profile->table_name_fields;
     814                        $sql           = "SELECT * FROM {$table_name} WHERE id IN ({$uncached_ids_sql})";
     815                        $queried_fdata = $wpdb->get_results( $sql );
     816
     817                        // Reset the field IDs array
     818                        $field_ids = array();
     819
     820                        // Put that data into the placeholders created earlier,
     821                        // and add it to the cache
     822                        if ( ! empty( $queried_fdata ) ) {
     823                                foreach ( $queried_fdata as $fdata ) {
     824                                        $field_ids[] = $fdata->id;
     825                                        wp_cache_set( $fdata->id, $fdata, 'bp_xprofile_fields' );
     826                                }
     827                        }
     828                }
     829
     830                // Return newly cached field IDs
     831                return $field_ids;
     832        }
     833
     834        public static function get_type( $field_id = 0 ) {
     835
    469836                // Bail if no field ID
    470837                if ( empty( $field_id ) ) {
    471838                        return false;
    472839                }
    473840
    474                 $bp   = buddypress();
    475                 $sql  = $wpdb->prepare( "SELECT type FROM {$bp->profile->table_name_fields} WHERE id = %d", $field_id );
    476                 $type = $wpdb->get_var( $sql );
     841                // Attempt to get the field
     842                $field = new BP_XProfile_Field( $field_id );
    477843
    478                 // Return field type
    479                 if ( ! empty( $type ) ) {
    480                         return $type;
     844                // Bail if no field found
     845                if ( empty( $field->type ) ) {
     846                        return false;
    481847                }
    482848
    483                 return false;
     849                return $field->type;
    484850        }
    485851
    486852        /**
     
    519885         *
    520886         * @since BuddyPress (1.5.0)
    521887         *
    522          * @global object $wpdb
    523          * @param  string $field_name
     888         * @param string $field_name
    524889         *
    525890         * @return boolean
    526891         */
    527892        public static function get_id_from_name( $field_name = '' ) {
    528                 global $wpdb;
    529893
    530                 $bp = buddypress();
     894                // Bail if no field ID
     895                if ( empty( $field_name ) ) {
     896                        return false;
     897                }
    531898
    532                 if ( empty( $bp->profile->table_name_fields ) || empty( $field_name ) ) {
     899                // Attempt to get the field
     900                $fields = self::get( array(
     901                        'name'      => $field_name,
     902                        'parent_id' => '0'
     903                ) );
     904
     905                // Return field if found
     906                if ( empty( $fields ) ) {
    533907                        return false;
    534908                }
    535909
    536                 $sql = $wpdb->prepare( "SELECT id FROM {$bp->profile->table_name_fields} WHERE name = %s AND parent_id = 0", $field_name );
     910                // Take the first field
     911                $field = reset( $fields );
    537912
    538                 return $wpdb->get_var( $sql );
     913                // Return false if not found
     914                return $field->id;
    539915        }
    540916
    541917        /**
     
    552928         * @return boolean
    553929         */
    554930        public static function update_position( $field_id, $position = null, $field_group_id = null ) {
    555                 global $wpdb;
    556931
    557932                // Bail if invalid position or field group
    558933                if ( ! is_numeric( $position ) || ! is_numeric( $field_group_id ) ) {
     
    560935                }
    561936
    562937                // Get table name and field parent
    563                 $table_name = buddypress()->profile->table_name_fields;
    564                 $sql        = $wpdb->prepare( "UPDATE {$table_name} SET field_order = %d, group_id = %d WHERE id = %d", $position, $field_group_id, $field_id );
    565                 $parent     = $wpdb->query( $sql );
     938                $field              = new BP_XProfile_Field( $field_id );
     939                $field->field_order = $position;
     940                $field->group_id    = $field_group_id;
    566941
    567                 // Update $field_id with new $position and $field_group_id
    568                 if ( ! empty( $parent ) && ! is_wp_error( $parent ) ) {
     942                // Bail if field did not save - pass `true` to prevent option deletion
     943                if ( ! $field->save( true ) ) {
     944                        return false;
     945                }
    569946
    570                         // Update any children of this $field_id
    571                         $sql = $wpdb->prepare( "UPDATE {$table_name} SET group_id = %d WHERE parent_id = %d", $field_group_id, $field_id );
    572                         $wpdb->query( $sql );
     947                // Regather the field and its children
     948                $field    = new BP_XProfile_Field( $field_id );
     949                $children = $field->get_children();
    573950
    574                         return $parent;
     951                // If child fields exist, update them
     952                if ( ! empty( $children ) ) {
     953
     954                        // Loop through children and update field group ID
     955                        foreach ( $children as $option_field ) {
     956                                $option           = new BP_XProfile_Field( $option_field->id );
     957                                $option->group_id = $field->group_id;
     958                                $option->save( true );
     959                        }
    575960                }
    576961
    577                 return false;
     962                return true;
    578963        }
    579964
    580965        /**
     
    6351020                                $this->description = $_POST['description'];
    6361021                                $this->is_required = $_POST['required'];
    6371022                                $this->type        = $_POST['fieldtype'];
    638                                 $this->order_by    = $_POST["sort_order_{$this->type}"];
     1023                                $this->order_by    = ! empty( $_POST["sort_order_{$this->type}"] ) ? $_POST["sort_order_{$this->type}"] : '';
    6391024                                $this->field_order = $_POST['field_order'];
    6401025                        }
    6411026                } else {
     
    6801065                                                        // Output the required metabox
    6811066                                                        $this->required_metabox();
    6821067
    683                                                         // Output the field visibility metaboxes
     1068                                                        // Output the field visibility metabox
    6841069                                                        $this->visibility_metabox();
    6851070
     1071                                                        // Output the signup metabox
     1072                                                        $this->signup_metabox();
     1073
    6861074                                                        /**
    6871075                                                         * Fires after XProfile Field sidebar metabox.
    6881076                                                         *
     
    9021290        }
    9031291
    9041292        /**
     1293         * Output the metabox for enabling this field to appear on user registration
     1294         *
     1295         * @since BuddyPress (2.3.0)
     1296         */
     1297        private function signup_metabox() {
     1298        ?>
     1299
     1300                <div class="postbox">
     1301                        <h3><label for="signup-field"><?php _e( 'Sign Ups', 'buddypress' ); ?></label></h3>
     1302                        <div class="inside">
     1303                                <ul>
     1304                                        <li>
     1305                                                <input type="checkbox" id="signup-position" name="signup-position" value="1" <?php checked( $this->signup_position, ! null ); ?> />
     1306                                                <label for="signup-position"><?php esc_html_e( 'Display on Registration', 'buddypress' ); ?></label>
     1307                                        </li>
     1308                                </ul>
     1309                        </div>
     1310                </div>
     1311
     1312        <?php
     1313        }
     1314
     1315        /**
    9051316         * Output the metabox for setting what type of field this is
    9061317         *
    9071318         * @since BuddyPress (2.3.0)
     
    9751386                // Compare & return
    9761387                return (bool) ( 1 === (int) $field_id );
    9771388        }
     1389
     1390        /**
     1391         * Purge caches relevant to field updates
     1392         *
     1393         * @since BuddyPress (2.3.0)
     1394         */
     1395        private function purge_caches() {
     1396
     1397                // Delete the cached value for this field
     1398                wp_cache_delete( $this->id, 'bp_xprofile_fields' );
     1399
     1400                // Bust cache of parent field
     1401                if ( ! empty( $this->parent_id ) ) {
     1402                        wp_cache_delete( $this->parent_id, 'bp_xprofile_fields' );
     1403                }
     1404
     1405                // Bust cache of parent group
     1406                if ( ! empty( $this->group_id ) ) {
     1407                        wp_cache_delete( 'all',           'bp_xprofile_groups' );
     1408                        wp_cache_delete( $this->group_id, 'bp_xprofile_groups' );
     1409                }
     1410
     1411        }
    9781412}
  • src/bp-xprofile/classes/class-bp-xprofile-group.php

     
    301301                        return $groups;
    302302                }
    303303
     304                /** Fields ************************************************************/
     305
    304306                // Get the group ids from the groups we found
    305307                $group_ids = wp_list_pluck( $groups, 'id' );
    306308
     
    312314                        return $groups;
    313315                }
    314316
    315                 // Setup IN query from group IDs
    316                 $group_ids_in = implode( ',', (array) $group_ids );
    317 
    318317                // Support arrays and comma-separated strings
    319318                $exclude_fields_cs = wp_parse_id_list( $r['exclude_fields'] );
    320319
    321320                // Visibility - Handled here so as not to be overridden by sloppy use of the
    322321                // exclude_fields parameter. See bp_xprofile_get_hidden_fields_for_user()
    323322                $hidden_user_fields = bp_xprofile_get_hidden_fields_for_user( $r['user_id'] );
    324                 $exclude_fields_cs  = array_merge( $exclude_fields_cs, $hidden_user_fields );
    325                 $exclude_fields_cs  = implode( ',', $exclude_fields_cs );
     323                $exclude_field_ids  = array_filter( array_merge( $exclude_fields_cs, $hidden_user_fields ) );
    326324
    327                 // Setup IN query for field IDs
    328                 if ( ! empty( $exclude_fields_cs ) ) {
    329                         $exclude_fields_sql = "AND id NOT IN ({$exclude_fields_cs})";
    330                 } else {
    331                         $exclude_fields_sql = '';
    332                 }
    333 
     325                // Setup ::get() arguments
    334326                // Fetch the fields
    335                 $fields    = $wpdb->get_results( "SELECT id, name, description, type, group_id, is_required FROM {$bp->profile->table_name_fields} WHERE group_id IN ( {$group_ids_in} ) AND parent_id = 0 {$exclude_fields_sql} ORDER BY field_order" );
     327                $fields = BP_XProfile_Field::get( array(
     328                        'exclude'           => $exclude_field_ids,
     329                        'group_id'          => $group_ids,
     330                        'parent_id'         => '0',
     331                        'update_meta_cache' => false, // for now
     332                        'fetch_data'        => false  // for now
     333                ) );
     334
     335                // Pluck the ID's
    336336                $field_ids = wp_list_pluck( $fields, 'id' );
    337337
    338338                // Store field IDs for meta cache priming
     
    343343                        return $groups;
    344344                }
    345345
     346                /** Field Data ********************************************************/
     347
    346348                // Maybe fetch field data
    347349                if ( ! empty( $r['fetch_field_data'] ) ) {
    348350
     
    361363                                        $maybe_value = maybe_unserialize( $data->value );
    362364
    363365                                        // Valid field values of 0 or '0' get caught by empty(), so we have an extra check for these. See #BP5731
    364                                         if ( ( ! empty( $maybe_value ) || '0' == $maybe_value ) && false !== $key = array_search( $data->field_id, $field_ids ) ) {
     366                                        if ( ( ! empty( $maybe_value ) || '0' === $maybe_value ) && false !== $key = array_search( $data->field_id, $field_ids ) ) {
    365367
    366368                                                // Fields that have data get removed from the list
    367369                                                unset( $field_ids[ $key ] );
     
    369371                                }
    370372
    371373                                // The remaining members of $field_ids are empty. Remove them.
    372                                 foreach( $fields as $field_key => $field ) {
     374                                foreach ( $fields as $field_key => $field ) {
    373375                                        if ( in_array( $field->id, $field_ids ) ) {
    374376                                                unset( $fields[ $field_key ] );
    375377                                        }