I am trying to create a custom field in the product attributes in Woocommerce. This to be able to select if an attribute is highlighted or not. For example:
I have found the solution to my problem. I share the code in case someone is useful. Regards!
add_action('woocommerce_after_product_attribute_settings', 'wcb_add_product_attribute_is_highlighted', 10, 2);
add_action('wp_ajax_woocommerce_save_attributes', 'wcb_ajax_woocommerce_save_attributes', 10);
function get_attribute_highlighted($id, $i) {
global $post;
$id = sanitize_title($id);
$id = strtolower($id);
$val = get_post_meta( $post->ID, "attribute_".$id."_highlighted_".$i, true);
return !empty($val) ? $val : false;
}
function wcb_add_product_attribute_is_highlighted($attribute, $i=0) {
$value = get_attribute_highlighted($attribute->get_name(), $i); ?>
<tr>
<td>
<div class="enable_highlighted">
<label><input type="hidden" name="attribute_highlighted[<?php echo esc_attr( $i ); ?>]" value="0" /><input type="checkbox" class="checkbox" <?php checked( $value, true ); ?> name="attribute_highlighted[<?php echo esc_attr( $i ); ?>]" value="1" /> <?php esc_html_e( 'Highlight attribute', $this->wcb ); ?></label>
</div>
</td>
</tr>
<?php
}
function wcb_ajax_woocommerce_save_attributes() {
check_ajax_referer( 'save-attributes', 'security' );
parse_str( $_POST['data'], $data );
$post_id = absint( $_POST['post_id'] );
if(array_key_exists("attribute_highlighted", $data) && is_array($data["attribute_highlighted"])) {
foreach($data["attribute_highlighted"] as $i => $val) {
$attr_name = sanitize_title($data["attribute_names"][$i]);
$attr_name = strtolower($attr_name);
update_post_meta( $post_id, "attribute_".$attr_name."_highlighted_".$i, wc_string_to_bool($val) );
}
}
}
In the end the only thing I had to add to my code was a hidden input with the same name as the checkbox but with a value of 0: <input type="hidden" name="attribute_highlighted[<?php echo esc_attr( $i ); ?>]" value="0" />
Here an image of the result (https://i.stack.imgur.com/VscT1.jpg). By clicking on save the value of the checkbox is maintained. The value is saved in a post_meta of the post that you are modifying. This is useful if you want to highlight a specific attribute in the front end.
I appreciate the help of @LoicTheAztec :)
@Jesús Magallón's
Answer need little modifications.
Remove the function get_attribute_highlighted()
and replace this line
$value = get_attribute_highlighted($attribute->get_name(), $i);
TO
global $post;
$post_id = isset($_POST['post_id']) ? absint($_POST['post_id']) : $post->ID ;
$value = get_post_meta($post_id , "attribute_description".$i, true);
It will show ajax saved value instance of empty;
And Change hooks
add_action('wp_ajax_woocommerce_save_attributes', 'wcb_ajax_woocommerce_save_attributes', 10);
TO
add_action('wp_ajax_woocommerce_save_attributes', 'wcb_ajax_woocommerce_save_attributes', 0);
perfect code but change the hook
add_action('wp_ajax_woocommerce_save_attributes', 'wcb_ajax_woocommerce_save_attributes', 10);
to
add_action('wp_ajax_woocommerce_save_attributes', 'wcb_ajax_woocommerce_save_attributes', 0);
As I struggled with the same issue I have tried using the code from Jesus Magallon. However, it did not work.
I found out that the priority of wp_ajax_woocommerce_save_attributes
needed to be set to 0, otherwise the callback is not run for some reason.
Forthermore, if we only use $post->ID
for get_post_meta()
the correct results state of the checkbox will only be visible on page reload. To make sure the selected state is also visible direclty after ajax saving/reloading, we need to use $post_id = isset( $_POST['post_id'] ) ? absint( $_POST['post_id'] ) : $post->ID;
instead.
Here the final version that should work perfectly for everyone:
add_action( 'woocommerce_after_product_attribute_settings', 'wcb_add_product_attribute_is_highlighted', 10, 2);
add_action( 'wp_ajax_woocommerce_save_attributes', 'wcb_ajax_woocommerce_save_attributes', 0);
function get_attribute_highlighted( $attribute_name, $i ) {
global $post;
// ID for either from ajax or from post
$post_id = isset( $_POST['post_id'] ) ? absint( $_POST['post_id'] ) : $post->ID ;
$attribute_name = strtolower( sanitize_title( $attribute_name ) );
$val = get_post_meta( $post_id, 'attribute_' . $attribute_name . '_highlighted_' . $i, true );
return !empty( $val ) ? $val : false;
}
function wcb_add_product_attribute_is_highlighted( $attribute, $i=0 ) {
$value = get_attribute_highlighted($attribute->get_name(), $i); ?>
<tr>
<td>
<div class="enable_highlighted">
<label>
<input type="hidden" name="attribute_highlighted[<?php echo esc_attr( $i ); ?>]" value="0" />
<input type="checkbox" class="checkbox" <?php checked( $value, true ); ?> name="attribute_highlighted[<?php echo esc_attr( $i ); ?>]" value="1" />
<?php esc_html_e( 'Highlight attribute', 'textdomain' ); ?>
</label>
</div>
</td>
</tr>
<?php
}
function wcb_ajax_woocommerce_save_attributes() {
check_ajax_referer( 'save-attributes', 'security' );
parse_str( $_POST['data'], $data );
$post_id = absint( $_POST['post_id'] );
if( array_key_exists( 'attribute_highlighted', $data ) && is_array( $data['attribute_highlighted'] ) ) {
foreach( $data['attribute_highlighted'] as $i => $val ) {
$attr_name = sanitize_title( $data['attribute_names'][$i] );
$attr_name = strtolower( $attr_name );
update_post_meta( $post_id, 'attribute_' . $attr_name . '_highlighted_' . absint( $i ), wc_string_to_bool( $val ) );
}
}
}