0

I have this code. When I save it, the user levels adding and gives time select input next to it. But when I give different time to levels, for example: Level 1: 2 weeks, Level 2: 9 Months

If saves only the last element, then all inputs display that value. How can I save different times? Where do I wrong?

//USER EDIT IN ADMIN DASHBOARD
add_action( 'show_user_profile', 'crf_show_extra_profile_fields' );
add_action( 'edit_user_profile', 'crf_show_extra_profile_fields' );

function crf_show_extra_profile_fields( $user ) {
    $user_levels = rua_get_user($user->ID)->get_level_ids();
    $elements = array();
    foreach ($user_levels as $user_level) {
        $present_date = date("Y-m-d");
        $end_time = get_the_author_meta( $user_level, $user->ID);
        $effectiveDate = strtotime($end_time, strtotime(date("Y-m-d")));
        $time = date("d/m/y", $effectiveDate);
        $elements[] = get_the_title($user_level) . 
        ' ->  <select name="' .$user_level. '" id="time-selector" style="width:180px;">
              <option value="default">Süre Seçiniz</option>
              <option value="+14 day" '.selected( $end_time, "+14 day"). '>2 Hafta</option>
              <option value="+9 months" '.selected( $end_time, "+9 months"). '>9 Ay</option>
              <option value="+12 months" ' .selected( $end_time, "+12 months"). '>12 Ay</option>
              <option value="+7 day" ' .selected( $end_time, "+7 day"). '>Uzat</option>
              </select>'  . $present_date . '   ' . $time .  '<br><br>';
    }
}


//SAVING DATE OF EACH LEVEL    
add_action( 'personal_options_update', 'crf_update_profile_fields' );
add_action( 'edit_user_profile_update', 'crf_update_profile_fields' );

function crf_update_profile_fields( $user_id ) {
    $user_levels = rua_get_user($user_id)->get_level_ids();
    foreach ($user_levels as $user_level) {
        update_user_meta( $user_id, $user_level, $_POST[ $user_level ] );
    }
}

//DELETING LEVEL
function my_demo_cronjob_action () {
    $present_date = date("Y-m-d");
    $user = get_user_by('id',26);
    $user_levels = rua_get_user($user)->get_level_ids(false, false, true);

    foreach ($user_levels as $level) {
      $end_time = get_the_author_meta( $level, $user->ID);
      $effectiveDate = strtotime($end_time, strtotime(date("Y-m-d")));
      $time = date("d/m/y", $effectiveDate);
      if ($present_date > $time) {
        rua_get_user($user)->remove_level($level);
      }
    }
}
add_action('my_demo_cronjob_action', 'my_demo_cronjob_action');
21
  • A side-note, you should use get_user_meta rather than get_the_author_meta
    – Tom J Nowell
    Commented Nov 17, 2020 at 15:59
  • I did not understand. get_user_meta will solve it directly?
    – freedom667
    Commented Nov 17, 2020 at 20:33
  • No, if it did I would have left an answer rather than a comment, you should still use get_user_meta instead, get_the_author_meta is innapropriate for this use case
    – Tom J Nowell
    Commented Nov 18, 2020 at 10:27
  • my problem is, how can I store the meta as multiple
    – freedom667
    Commented Nov 18, 2020 at 13:31
  • I know, as I said it was a comment, not an answer. Note that get_user_meta can do things that get_the_author_meta cannot. Technically get_the_author_meta shouldn't work here as the field parameter should not be able t accept arbitrary meta key values as there's a predefined whitelist, which means any answer will likely require get_user_meta, if not for that reason but because of its 3rd parameter. It is not possible to store the same meta key multiple times then retrieve them with get_the_author_meta, but it is with get_user_meta.
    – Tom J Nowell
    Commented Nov 18, 2020 at 13:38

1 Answer 1

0

Your HTML select tags for each level all have the same name and ID, and will overwrite each other. They must be unique. You will need separate names, IDs, and meta for each user level input.

Likewise, the user meta keys need to be unique. The code also needs to use get_user_meta instead ( get_the_author_meta is only to be used inside a post loop ).

I suggest using something similar to this:

    foreach ($user_levels as $user_level) {
        update_user_meta( $user_id, 'time-selector-' . $user_level, $_POST[ 'time-selector' . $user_level ] );
    }

Then changing your input names and IDs accordingly. e.g. <select name='time-selector-' . $user_level . 'You will also need to adjust your get_user_meta call to use the new keys

There is another mistake in your code however. selected does not return a string, it outputs it, so the selected="selected" HTML will be output in the wrong place. You need to pass a 3rd parameter false to make it return, otherwise your HTML markup will be incorrect, and the selected attribute will be displayed before the input markup is displayed.

Here is an example:

Saving the meta:

$rua_user = rua_get_user( $user->ID );
$user_levels = $rua_user->get_level_ids();

// save existing values if they exist
foreach ( $user_levels as $level ) {
    $metakey = 'time-selector-' . $level;
    if ( isset( $_POST[ $metakey ] ) ) {
        update_user_meta( $user_id, $metakey, $_POST[ $metakey ] );
    }
}

Displaying the input:

$choices = [
    'two'  => 'Two Weeks',
    'nine' => '9 months',
];

$rua_user = rua_get_user( $user->ID );
$user_levels = $rua_user->get_level_ids();

foreach ( $user_levels as $level ) {
    $metakey = 'time-selector-' . $level;
    $time    = get_user_meta( $user->ID, $metakey, true );
    ob_start();
    echo esc_html( get_the_title( $level ) ) . ' -> ';
    ?>
    <select
        name='time-selector-<?php echo esc_attr( $level ); ?>'
        id='time-selector-<?php echo esc_attr( $level ); ?>'
        style='width:180px;'
    >
        <option value='default'>Select time</option>
        <?php
        foreach ( $choices as $value => $label ) {
            ?>
            <option
                value="<?php echo esc_attr( $value ); ?>"
                <?php selected( $value, $time ); ?>
            >
                <?php echo esc_html( $label ); ?>
            </option>
            <?php
        }
        ?>
    </select>
    <br>
    <br>
    <?php
    $html = ob_get_clean();
    $elements[] = $html;
}
// ... etc

Note several important things:

  • All levels have unique and independent HTML markup, and post meta
  • Nothing is shared between each field, if things were shared they would not be separate
  • I used an output buffer to make the HTML easier to read and generate
  • I added escaping, an important security feature
  • The list of times is no longer hardcoded, and was moved to a separate array to simplify the code and reduce repetition. This also means they can be filtered, added to, etc
  • The save code is in a separate snippet, handling post/user save should not happen on the same hook as displaying the data.
    • By putting the save code inside the display code in your original question, you may have introduced a bug
  • Because the user meta keys have changed, all prior data will need to be re-saved. This should not be an issue as the prior data is broken due to the way your original code worked. Any data loss that could occurred already happened before you wrote the question.
  • If you try to use this snippet, you will not see the full list of times. I deliberately limited the array to 2 entries to prevent people using this as a copy paste solution. Anybody with beginner level PHP skills can update the array to add the other choices
20
  • my select menu is not multiple. it has not to be multiple. $menu variable will next to each level. let me show you with some pictures. Also get_user_meta not working. imgur.com/GQ25QrA - imgur.com/q2O4XUR maybe I could explain with pictures.
    – freedom667
    Commented Nov 19, 2020 at 7:48
  • @freedom667 please edit your question to include that information, it significantly changes the meaning of your question
    – Tom J Nowell
    Commented Nov 19, 2020 at 9:38
  • nothing changed, also get_user_meta returns null
    – freedom667
    Commented Nov 19, 2020 at 10:14
  • @freedom667 I can't see the code changes you've made to use get_user_meta so I don't know how to help or what went wrong. TLDR all your inputs have the same name, and you only store the value once. If you have 5 user levels, then you need 5 inputs, 5 input names, 5 IDs, 5 meta keys, not 1
    – Tom J Nowell
    Commented Nov 19, 2020 at 10:29
  • but the levels can be 4,3 or 1. So, the levels are not fixed. one user has 5 levels, another user has 2 levels. it works this way.
    – freedom667
    Commented Nov 19, 2020 at 11:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.