Store custom field’s multiple values in one user meta key

There are “month_of_birth“, “day_of_birth“,
year_of_birth“.

How to store them in one meta key (‘birth_date‘) ?

If you mean to replace all the three meta keys with one single meta key, then you can save the birth_date meta as an array, so that the value would be something like this:

array(
    'month' => 'august',
    'day'   => '27',
    'year'  => '2018'
)

Here are the steps:

  1. In the birthdate_show_extra_profile_fields(), retrieve the
    birth_date meta value like this:

    function birthdate_show_extra_profile_fields( $user ) {
        // Get the birth date, which is an array of month, day, and year.
        $birth_date = (array) get_user_meta( $user->ID, 'birth_date', true );
        ?>
    
  2. Then replace the name of the drop-down menus (i.e. select
    fields), and replace the code for retrieving the individual birth
    month, day, and year:

    For the birth month menu:

    <select name="month_of_birth" id="month_of_birth"> <!-- before -->
    <select name="birth_date[month]" id="month_of_birth"> <!-- after -->
    
    $_value = trim( get_user_meta( $user->ID, 'month_of_birth', true ) ); // before
    $_value = isset( $birth_date['month'] ) ? $birth_date['month'] : ''; // after
    

    For the birth day menu:

    <select name="day_of_birth" id="day_of_birth"> <!-- before -->
    <select name="birth_date[day]" id="day_of_birth"> <!-- after -->
    
    $_value = trim( get_user_meta( $user->ID, 'day_of_birth', true ) ); // before
    $_value = isset( $birth_date['day'] ) ? $birth_date['day'] : ''; // after
    

    For the birth year menu:

    <select name="year_of_birth" id="year_of_birth"> <!-- before -->
    <select name="birth_date[year]" id="year_of_birth"> <!-- after -->
    
    $_value = trim( get_user_meta( $user->ID, 'year_of_birth', true ) ); // before
    $_value = isset( $birth_date['year'] ) ? $birth_date['year'] : ''; // after
    
  3. Then use this for saving the birth_date meta value:

    function birthdate_save_extra_user_profile_fields( $user_id ) {
        if ( !current_user_can( 'edit_user', $user_id ) )
            return false;
    
        // Make sure we have a valid POSTed data, and if yes, then
        // sanitize/clean each array item.
        $birth_date = isset( $_POST['birth_date'] ) ?
            array_map( 'sanitize_text_field', $_POST['birth_date'] ) : array();
    
        update_user_meta( $user_id, 'birth_date', $birth_date );
    }
    

UPDATE

You can retrieve the saved birth_date meta value like this:

// Note that the last/third parameter is TRUE and not FALSE.
$birth_date = get_user_meta( $user_id, 'birth_date', true );

echo $birth_date['month']; // e.g. august
echo $birth_date['day'];   // e.g. 27
echo $birth_date['year'];  // e.g. 2018

If you want the month name to start in uppercase, apply ucfirst() on the month name, like this:

echo ucfirst( $birth_date['month'] ); // e.g. August

So your user_birthdate_info_shortcode() could be rewritten into this:

function user_birthdate_info_shortcode() {
    if(is_user_logged_in()) {
        $user_id = get_current_user_id();
        $birth_date = get_user_meta($user_id, 'birth_date', true);

        echo ucfirst( $birth_date['month'] ) . '&nbsp;' . // apply ucfirst()
            $birth_date['day'] . '&nbsp;' . $birth_date['year'];
    }
}

Alternatively, just save the month name (e.g. August) instead of its slug/key (e.g. august). So in the birthdate_show_extra_profile_fields() function, change this: (you’d need to re-indent the code)

foreach ( array(
    'not-selected' => '',
    'january' => 'January',
    'february' => 'February',
    'march' => 'March',
    'april' => 'April',
    'may' => 'May',
    'june' => 'June',
    'july' => 'July',
    'august' => 'August',
    'september' => 'September',
    'october' => 'October',
    'november' => 'November',
    'december' => 'December',
) as $value => $label ) :

to:

foreach ( array(
    '',
    'January', 'February', 'March',     'April',   'May',      'June',
    'July',    'August',   'September', 'October', 'November', 'December',
) as $label ) :
    $value = $label; // use the label as the value

So your user_birthdate_info_shortcode() could be rewritten into this:

function user_birthdate_info_shortcode() {
    if(is_user_logged_in()) {
        $user_id = get_current_user_id();
        $birth_date = get_user_meta($user_id, 'birth_date', true);

        echo $birth_date['month'] . '&nbsp;' . // ucfirst() not necessary
            $birth_date['day'] . '&nbsp;' . $birth_date['year'];
    }
}