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');
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');
Share
Improve this question
edited Nov 26, 2020 at 6:39
freedom667
asked Nov 17, 2020 at 15:24
freedom667freedom667
56 bronze badges
21
|
Show 16 more comments
1 Answer
Reset to default 0Your 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
get_user_meta
rather thanget_the_author_meta
– Tom J Nowell ♦ Commented Nov 17, 2020 at 15:59get_user_meta
instead,get_the_author_meta
is innapropriate for this use case – Tom J Nowell ♦ Commented Nov 18, 2020 at 10:27get_user_meta
can do things thatget_the_author_meta
cannot. Technicallyget_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 requireget_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 withget_the_author_meta
, but it is withget_user_meta
. – Tom J Nowell ♦ Commented Nov 18, 2020 at 13:38