The main issue with your code is that the form submission will always have the same value. This could be seen by debugging $_POST
where you check if $_POST['submit']
was set.
I set up a custom database table and added some dummy data. I think this more or less mirrors your setup.
Here is the code that creates the DB table and adds some sample data.
/**
* Quick and dirty custom DB table and data creation.
* Only creates the DB and data if the table does not yet exists.
*/
function wpse_create_custom_table_example() {
global $wpdb;
$table_name = $wpdb->prefix . 'custom_table_test';
$query = $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->esc_like( $table_name ) );
// Bail if the DB already exists.
if ( $wpdb->get_var( $query ) === $table_name ) {
return;
}
// Create table.
$sql = "CREATE TABLE `{$table_name}` (
ID bigint(20) unsigned NOT NULL AUTO_INCREMENT,
name varchar(20),
PRIMARY KEY (ID)
) {$wpdb->get_charset_collate()}";
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
dbDelta( $sql );
// Define dummy data. These are the NKOTB, btw.
$names = [
'Danny',
'Donny',
'Joe',
'Jon',
'Jordan',
];
// Add dummy data.
foreach ( $names as $name ) {
$sql = $wpdb->prepare(
"INSERT INTO `$table_name` (`name`) values (%s)",
esc_sql( $name )
);
$wpdb->query($sql);
}
}
add_action( 'init', 'wpse_create_custom_table_example' );
Here is the reworked code. Each submit button now contains the name pulled from the DB. The appropriate value will be saved to user meta when the user (who must be logged in, of course) clicks a button. I also added a nonce field and some other security measures. There’s still room for improvement, but this Gets R Done.
/**
* Output a form which lists Names from the `custom_table_test` table.
* When clicking a name, the value of the name will be saved under
* user meta for the current user using the key, `programma`.
*
* Each time a name is clicked, that value will replace the previous value.
*
* To use: Call this function from within the loop on the single post template.
*/
function wpse_update_user_meta_from_db() {
if ( is_single() ) {
global $wpdb;
// This adds the prefix which is set by the user upon installation of WordPress.
$table_name = $wpdb->prefix . 'custom_table_test';
// This will get the data from your table.
$retrieve_data = $wpdb->get_results( "SELECT `name` FROM {$table_name}" );
//error_log( var_export( $retrieve_data, true ) );
?>
<form action="#" enctype="multipart/form-data" method="post">
<?php wp_nonce_field( 'set_programma_action', 'set_programma' ); ?>
<table>
<?php foreach ( $retrieve_data as $retrieved_data ) { ?>
<tr>
<th>Programma:</th>
<td style="vertical-align: middle;"><?php echo esc_html( $retrieved_data->name ); ?></td>
<th>
<button name="programma" type="submit"
value="<?php echo esc_attr( $retrieved_data->name ); ?>">Abonneer</button>
</th>
</tr>
<?php } ?>
</table>
</form>
<?php
// Verify nonce and save data if the user is logged in.
// Nonce docs: https://developer.wordpress.org/themes/theme-security/using-nonces/
if (
isset( $_POST['programma'] ) &&
isset( $_POST['set_programma'] ) && wp_verify_nonce( $_POST['set_programma'], 'set_programma_action' )
) {
$data = filter_input( INPUT_POST, 'programma', FILTER_SANITIZE_STRING );
$current_user_id = get_current_user_id();
if ( $current_user_id && ! empty( $data ) ) {
update_user_meta( $current_user_id, 'programma', $data );
}
}
}
}
Add the functions above to your theme’s functions.php
or into a plugin. Call wpse_update_user_meta_from_db()
inside your post/CPT single template.
Here’s what it looks like in a Twenty Twenty child theme:
Here we can see that data from our custom table was saved under the current user’s meta: