Duplicate values appended each time save checkbox values - php

I am trying to create a multiselect dropdown list using "jQuery UI MultiSelect Widget" (http://www.erichynds.com/blog/jquery-ui-multiselect-widget) on Wordpress template page and save checked options into database (Mysql) as a single string value.
And THE PROBLEM: duplicate values are appended (i.e A, B, A, B) each time I click Save form. The problem does not happen IF I select new options in this dropdown list. BTW, other fields like textbox, single-select dropdown or textarea are OK.
Below are 2 code segments that I believe the problem comes from, so someone please help me point out what's going wrong here. I have been worked around this problem for the whole week but NO luck! Thank you very much!
<?php
case 'maker_dropdown':
global $wpdb;
$makers = $wpdb->get_var( $wpdb->prepare( "SELECT field_values FROM ". $wpdb->prefix . "cp_ad_fields WHERE field_name = 'cp_maker';", "" ) );
$selected_makers = $wpdb->get_var( $wpdb->prepare( "SELECT meta_value FROM ". $wpdb->prefix . "usermeta WHERE meta_key = 'maker' AND user_id =" . $user->ID . ";", "" ) );
if ($makers) {
?>
<select name="<?php echo $field_id; ?>[]" class="regular-dropdown multiselect" multiple="multiple" >
<?php
$options = explode( ',', $makers);
$selected_options = explode( ',', $selected_makers);
foreach ( $options as $option) { // loop thru all available options
if ( in_array($option, $selected_options)) {
?>
<option name="<?php echo $option; ?>[]" selected="selected" value="<?php esc_attr_e($the_value); ?>"><?php esc_attr_e($option); ?></option>
<?php
}
else {
?>
<option value="<?php esc_attr_e($option); ?>"><?php esc_attr_e($option); ?></option>
<?php
}
} //endforeach
?>
</select>
<?php } //endif ?>
break;
This code segment is used to display multiselect dropdown list on front-end.
function ctm_profile_fields_save($user_id) {
global $ctm_extra_profile_fields;
foreach ($ctm_extra_profile_fields as $field_id => $field_values) :
$selected_options = implode(',', $_POST[$field_id]);
if ($field_values['type'] == 'maker_dropdown') {
update_user_meta( $user_id, $field_id, $selected_options );
}
else {
update_user_meta( $user_id, $field_id, sanitize_text_field( $_POST[$field_id] ) );
}
endforeach;
}
add_action('personal_options_update', 'ctm_profile_fields_save');
add_action('edit_user_profile_update', 'ctm_profile_fields_save');
This code segment is used to save multiselect dropdown list into database.

update_user_meta function allows for multiple meta entries with the same key.
When you read the existing makers for the user you may get ['A', 'B']. When you save the submitted form you add a new set of selected values ['A', 'B'] to what was there previously. This is why your values are duplicated.
There are two easy ways of solving this.
Option 1: Clear the meta key before saving it.
foreach ($ctm_extra_profile_fields as $field_id => $field_values) :
$selected_options = implode(',', $_POST[$field_id]);
delete_user_meta($user_id, $field_id);
if ($field_values['type'] == 'maker_dropdown') {
update_user_meta( $user_id, $field_id, $selected_options );
}
else {
update_user_meta( $user_id, $field_id, sanitize_text_field( $_POST[$field_id] ) );
}
endforeach;
Option 2: Specify previous value in the update_user_meta to not create duplicate entries
foreach ($ctm_extra_profile_fields as $field_id => $field_values) :
$selected_options = implode(',', $_POST[$field_id]);
if ($field_values['type'] == 'maker_dropdown') {
update_user_meta( $user_id, $field_id, $selected_options, $selected_options );
}
else {
update_user_meta( $user_id, $field_id, sanitize_text_field( $_POST[$field_id] ), sanitize_text_field( $_POST[$field_id] ) );
}
endforeach;

Related

WordPress custom post meta filter not displaying options when filter is set

I have two custom post types set up - "Books" and "Authors". I am using custom metadata which allows you to link a book to an author via a select box (by querying posts from the authors post type to create the select options).
This works fine, but I'm also trying to create a custom filter on the posts screen for the books post type that allows you to filter by author, which isn't behaving as expected. Here's the code I'm using to add the filter:
function book_filter() {
global $typenow;
global $wp_query;
if ( $typenow == 'book' ) {
$authors = new WP_Query(
array(
'post_type' => 'author',
'nopaging' => true
)
);
wp_reset_postdata();
/*
$authors = get_posts( array(
'post_type' => 'author',
'numberposts' => -1
));
*/
$current_author = '';
if( isset( $_GET['author'] ) ) {
$current_author = $_GET['author'];
} ?>
<select name="author" id="author">
<option value="all" <?php selected( 'all', $current_author ); ?>>All authors</option>
<?php
if ($authors->have_posts()) {
while ($authors->have_posts()) {
$authors->the_post();
if ($current_author == get_the_ID()) {
echo '<option value="' . get_the_ID() . '" selected>' . get_the_title() . '</option>';
} else {
echo '<option value="' . get_the_ID() . '">' . get_the_title() . '</option>';
}
}
}
/* foreach( $authors as $author ) { ?>
<option value="<?php echo $author->ID; ?>" <?php selected( $author->ID, $current_author ); ?>><?php echo get_the_title($author->ID); ?></option>
<?php } */
?>
</select>
<?php }
}
add_action( 'restrict_manage_posts', 'book_filter' );
function do_book_filter( $query ) {
global $pagenow;
$post_type = isset( $_GET['post_type'] ) ? $_GET['post_type'] : '';
if ( is_admin() && $pagenow=='edit.php' && $post_type == 'book' ) {
if (isset( $_GET['author'] ) && $_GET['author'] !='all' ) {
$query->query_vars['meta_key'] = 'author';
$query->query_vars['meta_value'] = $_GET['author'];
$query->query_vars['meta_compare'] = '=';
}
}
}
add_filter( 'parse_query', 'do_book_filter' );
Initially, all the authors are shown in the filter, and selecting an author to filter by does actually work. The problem is that, once it's been filtered, the authors disappear from the select box dropdown. I tried adding an else statement to if ($authors->have_posts()) {... and this confirmed that it isn't fetching posts from the authors post type after a filter has been set.
I'm also using another custom filter (removed from the code for simplicity) which just uses a standard array variable rather than a query and that one is working fine, so I guess it must something to do with the custom post type query.
You'll see in the code that I've tried get_posts (commented) as well as WP_Query but they both present the same issue.
Where am I going wrong here?

Can't sanitize select field with WordPress Categories

I'm adding a custom field to page that would select a blog category to feature on that page. All the other fields are working fine, so, i'll post code related only to this field. Getting error 500 when loading page editor.
$feat_blog = isset( $values['feat_blog'] ) ? esc_attr( $values['feat_blog'][0] ) : "";
This is the field itself
<select name="feat_blog" id="feat_blog" value="<?php echo $feat_blog; ?>">
<?php $categories = get_categories(); foreach($categories as $category) { ?>
<option value="<?php echo $category->slug ?>"> <?php echo $category->name ?></option>
<?php } ?>
</select>
And sanitization code that's actually causing trouble
if ( isset( $_POST['feat_blog'] )){
$valid_values = array(
categories = get_categories();
foreach($categories as $category) {
echo $category->slug,
}
);
$value = sanitize_text_field( $_POST['feat_blog'] );
if( in_array( $value, $valid_values ) ) {
update_post_meta( $post->ID, 'feat_blog', $value );
}
}
There are quite a few things wrong with your code here...
You are putting ; in an array and attempting to assign a variable there.
You are echoing in an array.
You are running functions inside an array.
You are missing the $ infront of the $categories variable.
if ( isset( $_POST['feat_blog'] )) {
$categories = get_categories();
$valid_values = array();
foreach($categories as $category) {
$valid_values[] = $category->slug;
}
$value = sanitize_text_field( $_POST['feat_blog'] );
if( in_array( $value, $valid_values ) ) {
update_post_meta( $post->ID, 'feat_blog', $value );
}
}
What I did here is I moved the $categories variable declaration outside of the foreach loop and set the $valid_values array BEFORE the loop. If you set it inside the loop it is going to reset every time the loop occurs. You also can't use ; inside of an array as that is intended to close the statement.

WooCommerce admin order edit save post

In WooCommerce, when I submit, how to catch a custom select field added in the order edit admin pages?
I have added this custom select field in the file class-wc-meta-box-order-data.php. I get this:
But I dont know how to catch or to save $_POST['vendor']
I have tried to add $_POST['vendor'] in wp-admin/post.php ,but it doesn't work.
This is the code that I have added:
<select class="wc-customer-search" id="customer_user" name="customer_user" data-placeholder="<?php esc_attr_e( 'Guest', 'woocommerce' ); ?>" data-allow_clear="true">
<option value="<?php echo esc_attr( $user_id ); ?>" selected="selected"><?php echo htmlspecialchars( $user_string ); ?></option>
</select>
<!--/email_off-->
</p>
<p> <label for="order_status">供應商: </label>
<select name="vendor">
<?php
global $wpdb;
$user_count = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->users" );
for($i=1;$i<=$user_count;$i++){
$user_info = get_userdata($i);
if (implode(', ', $user_info->roles)=='vendor')
echo "<option value=".$user_info->user_login.">$user_info->user_login</option>";
}
?>
</select></p>
How can I get the submitted value and how can I save it?
Overriding core files is something prohibited for developers. So this is not the correct way to do it.
The way to do it is using the available hooks in the source code, instead of overriding this core files, as you will loose everything when the plugin will be updated.
Replace all original core files
Add this code instead (I have make some minor necessary changes).
Here is the replacement code + a hook to save the data to the order meta data:
add_action( 'woocommerce_admin_order_data_after_order_details', 'custom_code_after_order_details', 10, 1 );
function custom_code_after_order_details ( $order ) {
// Get custom field value from '_vendor' meta key
$value = $order->get_meta('_vendor');
?>
<p> <label for="order_status">供應商: </label>
<select name="vendor">
<?php global $wpdb;
$user_count = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->users" );
echo '<option value="">Select a vendor</option>';
for ( $i=1; $i<=$user_count; $i++ ) {
$user_info = get_userdata($i);
if ( in_array('vendor', $user_info->roles) ){
$user_login = $user_info->user_login;
$selected = $value == $user_login ? 'selected' : '';
echo '<option '.$selected.' value="'.$user_login.'">'.$user_login.'</option>';
}
}
?>
</select></p>
<input type="hidden" name="custom_select_field_nonce" value="<?php echo wp_create_nonce(); ?>">
<?php
}
add_action( 'save_post', 'save_custom_code_after_order_details', 10, 1 );
function save_custom_code_after_order_details( $post_id ) {
// We need to verify this with the proper authorization (security stuff).
// Check if our nonce is set.
if ( ! isset( $_POST[ 'custom_select_field_nonce' ] ) ) {
return $post_id;
}
$nonce = $_REQUEST[ 'custom_select_field_nonce' ];
//Verify that the nonce is valid.
if ( ! wp_verify_nonce( $nonce ) ) {
return $post_id;
}
// If this is an autosave, our form has not been submitted, so we don't want to do anything.
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return $post_id;
}
// Check the user's permissions.
if ( 'page' == $_POST[ 'post_type' ] ) {
if ( ! current_user_can( 'edit_page', $post_id ) ) {
return $post_id;
}
} else {
if ( ! current_user_can( 'edit_post', $post_id ) ) {
return $post_id;
}
}
// Update the meta field in the database.
update_post_meta( $post_id, '_vendor', $_POST[ 'vendor' ] );
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
This code is tested and works.

Show authors only own courses in dropdown

I am using Buddypress groups and part of the Group set up is to associate it to a Post (it's a custom post type called 'course').
The problem is that when associating a group to a particular post, the dropdown shows Authors all sitewide posts, (i.e. including from other authors). I want it so they can only see, and select from, their own posts - i.e. associate their group to one of their posts.
The code that is behind the current dropdown (which shows all authors' posts) is:
<select name="bp_group_course" id="bp-group-course">
<option value="-1"><?php _e( '--Select--', 'buddypress-learndash' ); ?></option>
<?php
foreach ( $courses as $course ) {
$group_attached = get_post_meta( $course->ID, 'bp_course_group', true );
if ( !empty( $group_attached ) && ( '-1' != $group_attached ) && $course->ID != $group_status ) {
continue;
}
?><option value="<?php echo $course->ID; ?>" <?php echo (( $course->ID == $group_status )) ? 'selected' : ''; ?>><?php echo $course->post_title; ?></option><?php
}
?>
</select>
$courses seems to come from:
if ( ! empty( $course_id ) ) {
$courses = array( get_post( $course_id ) );
} elseif ( ! empty( $group_id ) ){
$courses = learndash_group_enrolled_courses( $group_id );
$courses = array_map( 'intval', $courses );
$courses = ld_course_list( array( 'post__in' => $courses, 'array' => true ) );
} else {
$courses = ld_course_list( array( 'array' => true ) );
}
How can I limit it to just the currently logged in user's posts?
Thanks in advance,

PHP: How to save multiple checkbox values instead of one

I'm trying to edit a WordPress front end user form plugin so that it will write away multiple check box values (from one of my custom fields) in a single SQL record. I need to do this so my query search form can search for all values checked off. Right now, if a user checks off more than one option, only one single value is being stored. How can I adjust this PHP code so that every value checked will be stored?
/**
* Prints a checkbox field
*
* #param array $attr
* #param int|null $post_id */
function checkbox( $attr, $post_id, $type ) {
$selected = isset( $attr['selected'] ) ? $attr['selected'] : array();
if ( $post_id ) {
$selected = explode( self::$separator, $this->get_meta( $post_id, $attr['name'], $type, true ) );
}
?>
<div class="wpuf-fields">
<span data-required="<?php echo $attr['required'] ?>" data-type="radio"></span>
<?php
if ( $attr['options'] && count( $attr['options'] ) > 0 ) {
foreach ($attr['options'] as $option) {
?>
<label>
<input type="checkbox" name="<?php echo $attr['name']; ?>[]" value="<?php echo esc_attr( $option ); ?>"<?php echo in_array( $option, $selected ) ? ' checked="checked"' : ''; ?> />
<?php echo $option; ?>
</label>
<?php
}
}
?>
Thanks in advance!

Categories