Wordpress widget: Checkbox not saving state - wordpress

I have a Wordpress widget with checkboxs. I am trying to set the default state to "checked" for one of the checkboxes by setting a variable in my defaults array to true. If I uncheck the box and try to save the widget the checkbox reverts back to being checked, so basically I can't uncheck the box.
I have other checkboxs with the same configuration and they are working correctly. Does anyone see anything wrong with my code below?
$defaults = array(
'widget' => 'cat',
'type' => 'list',
'selected' => 0,
'use_products' => 'true',
'title' => '',
'sub_title' => '',
'operator' => 'IN',
'print_before_widget' => 'true',
'print_after_widget' => 'true',
'hide_empty' => 'true',
'hide_on_cats' => 'false',
'custom_class' => ''
);
$instance = parse_args( $instance, $defaults );
extract( $instance );
<p>
<input class="checkbox"
<?php if ( isset( $use_products ) && $use_products=='true' ) { echo 'checked="checked"'; } ?>
id = "<?php echo $this->get_field_id( 'use_products' ); ?>"
name = "<?php echo $this->get_field_name( 'use_products' ); ?>"
value = "true"
type = "checkbox"
/>
<label for="<?php echo $this->get_field_id( 'use_products' ); ?>" ><?php _e( 'Show Product Categories', textdomain ); ?></label>
</p>

There may be several things wrong here but you may not be giving enough context.
I am assuming this is a snippet from inside the form() method of your widget. The form() method is passed the $instance variable, which contains the current values of all the widget settings. You dont appear to be using that at all. Your value for the checkbox is hardcoded as true, and your $defaults array isnt merged or overridden by anything - your just setting defaults and using them directly - your not using values from the database.
https://codex.wordpress.org/Widgets_API#Default_Usage
Edit
In your update method, for the checkbox, you should do something like the following...
public function update($new_instance, $old_instance){
$instance = array();
$instance['checkbox_key'] = ( ! empty( $new_instance['checkbox_key'] ) ) ? strip_tags( $new_instance['checkbox_key'] ) : '';
return $instance;
}
If this doesnt make sense in your context, you should update your answer to include the update() method.

Related

How to add custom button before Add to Cart form in WooCommerce Product Page and I want different links for different products?

How to add a custom button before Add to Cart form on WooCommerce Product Page? and I want different links for different products.
My PHP Code:
add_action( 'woocommerce_before_add_to_cart_form', 'learnalwayss_after_add_to_cart_btn' );
function learnalwayss_after_add_to_cart_btn() {
global $product;
if ( $product->get_id() == 149685 ) {
echo '<a class="button primary is-small box-shadow-4 box-shadow-2-hover" style="border-radius: 10px; background-color:#FFDB58 !important; color:black;" target="_blank" href="https://myurls.bio/learn_alwayss">Our Links</a>';
}
}
Your solution is simple and effective but you have to add every url manually in the source code.
The solution I am suggesting uses wp_postmeta to store the label and url of the button. This way, a regular user can add/change the value of the url instead of asking a developer to make every change.
We'll add 2 custom fields to the product page to store these values into metadata.
To add custom fields for the custom_button_url and custom_button_text metadata to the edit product page in WooCommerce, you can use the woocommerce_product_options_general_product_data hook to add the custom fields to the product data panel, and the woocommerce_process_product_meta hook to save the custom field values when the product is saved.
function custom_button_product_data_fields() {
global $post;
// Get the values of the "custom_button_url" and "custom_button_text" custom fields
$custom_button_url = get_post_meta( $post->ID, 'custom_button_url', true );
$custom_button_text = get_post_meta( $post->ID, 'custom_button_text', true );
// Add a custom field for the "custom_button_url" metadata
woocommerce_wp_text_input( array(
'id' => 'custom_button_url',
'label' => __( 'Custom Button URL', 'your-text-domain' ),
'placeholder' => 'http://',
'description' => __( 'Enter the URL for the custom button.', 'your-text-domain' ),
'type' => 'url',
'value' => $custom_button_url,
'custom_attributes' => array(
'pattern' => 'https?://.+',
),
) );
// Add a custom field for the "custom_button_text" metadata
woocommerce_wp_text_input( array(
'id' => 'custom_button_text',
'label' => __( 'Custom Button Text', 'your-text-domain' ),
'placeholder' => '',
'description' => __( 'Enter the text for the custom button.', 'your-text-domain' ),
'type' => 'text',
'value' => $custom_button_text,
) );
}
add_action( 'woocommerce_product_options_general_product_data', 'custom_button_product_data_fields' );
And to save the values into the wp_postmeta you can use woocommerce_process_product_meta hook
function save_custom_button_product_data_fields( $post_id ) {
// Save the value of the "custom_button_url" custom field
$custom_button_url = isset( $_POST['custom_button_url'] ) ? sanitize_text_field( $_POST['custom_button_url'] ) : '';
update_post_meta( $post_id, 'custom_button_url', $custom_button_url );
// Save the value of the "custom_button_text" custom field
$custom_button_text = isset( $_POST['custom_button_text'] ) ? sanitize_text_field( $_POST['custom_button_text'] ) : '';
update_post_meta( $post_id, 'custom_button_text', $custom_button_text );
}
add_action( 'woocommerce_process_product_meta', 'save_custom_button_product_data_fields' );
Now we only have to display the button using the woocommerce_before_add_to_cart_form hook. You can use any other hook on the product page to show the button in a different place.
function custom_button_before_add_to_cart() {
global $product;
$product_id = $product->get_id();
// Get the values of the "custom_button_url" and "custom_button_text" custom fields
$custom_button_url = get_post_meta( $product_id, 'custom_button_url', true );
$custom_button_text = get_post_meta( $product_id, 'custom_button_text', true );
// If the "custom_button_url" custom field has a value, show the button
if ( ! empty( $custom_button_url ) ) {
// If the "custom_button_text" custom field has a value, use it as the button text
if ( ! empty( $custom_button_text ) ) {
$button_text = $custom_button_text;
} else {
// If the "custom_button_text" custom field is empty, use the default button text
$button_text = __( 'Default Button Text', 'your-text-domain' );
}
// Use the value of the "custom_button_url" custom field as the button link
$button_link = $custom_button_url;
echo '' . esc_html( $button_text ) . '';
}
}
add_action( 'woocommerce_before_add_to_cart_form', 'custom_button_before_add_to_cart' );
This code enables you to use WordPress or ACF custom fields to add unique button links.
add_action( 'woocommerce_before_add_to_cart_form', 'button_custom_field' );
function button_custom_field() {
$wp = get_post_meta( get_the_ID(), 'wp_button', true );
$acf = class_exists('acf') ? get_field('acf_button') : '';
$field = $acf ? $acf : $wp;
if ( $field && is_singular('product') ) {
printf( '' . __( 'Custom Button' ) . '', $field );
}
}
Note : I wouldn't add the styling inline. Better to add it in your child themes stylesheet. Source

WordPress add field to checkout, can't add user meta to value

I'm trying to add an extra form field to woocommerce checkout, and populate it with an existing user meta value if exists, but I can't seem to get the value attribute to render.
$user_meta_billing_licence_number traces to the error log, and it will show up in the label if I append it to the label, and to the placeholder, if I append it to the placeholder, but not to the value attribute. What am I doing wrong?
add_filter('woocommerce_billing_fields', 'custom_billing_fields', 20 );
function custom_billing_fields( $fields ) {
// Add license field.
$user_id = get_current_user_id();
$user_meta_billing_licence_number = (string)get_user_meta( $user_id, 'billing_licence_number', true );
error_log('debug: line 117: billing_licence_number = '.$user_meta_billing_licence_number);
$fields['billing_licence_number'] = array(
'label' => __('License Number (for use on certificates)', 'woocommerce'),
'required' => false,
'class' => array('form-row-wide'),
'clear' => true,
'placeholder' => 'Recommended format: MA12345'.$user_meta_billing_licence_number,
'value' => $user_meta_billing_licence_number
);
return $fields;
}
So... looks like you can't pass the value in through this filter. You have to intercept it later, and override the value fetching during the printing of the fields:
<?php foreach ( $checkout->checkout_fields['billing'] as $key => $field ) : ?>
<?php
if($key == 'billing_licence_number') {
$uID = get_current_user_id();
woocommerce_form_field( $key, $field, get_user_meta($uID, 'billing_licence_number', true));
} else {
woocommerce_form_field( $key, $field, $checkout->get_value( $key ) );
}
?>
<?php endforeach; ?>

How to properly save a WordPress option containing HTML code?

Here's a screenshot of what the problem looks like:
And the HTML of that part of the WordPress options page looks like this:
So, in the WordPress admin area, I entered a piece of HTML code (to have a clickable link as the output on the frontend).
This was the code I had entered into that text input field on the backend:
<a title="Website Design London" href="../../website-design/">Website Design</a>
And while on the frontend that link is displaying OK, I'm seeing this mess (see screenshot) on the backend.
As far as I can tell the relevant PHP code is this:
$this->text(
'workdone',
esc_html__( 'Work done', 'mytheme' )
);
So, what is the proper way to save an option that contains HTML code?
And how can I fix the mess shown on the screenshot?
I had the same issue, and this code is working for me:
// render service label
public function render_service_label() {
$value = get_option( 'wbk_service_label', '' );
$value = htmlspecialchars( $value );
$html = '<input type="text" id="wbk_service_label" name="wbk_service_label" value="'.$value.'" >';
$html .= '<p class="description">' . __( 'Service label', 'wbk' ) . '</p>';
echo $html;
}
// validate service label
public function validate_service_label( $input ) {
$allowed_tags = array(
//formatting
'strong' => array(),
'em' => array(),
'b' => array(),
'i' => array(),
'br' => array(),
//links
'a' => array(
'href' => array(),
'class' => array()
),
//links
'p' => array(
'class' => array()
)
);
$input = wp_kses( $input, $allowed_tags );
return $input;
}
So, in the dashboard options page I use htmlspecialchars function
In frontend page I use like this:
$label = get_option( 'wbk_service_label', __( 'Select service', 'wbk' ) );

WordPress CMB2 - Get Option Value

I am using the example from the CMB2 snippets library to add a theme options page in WordPress
/**
* Hook in and register a metabox to handle a theme options page and adds a menu item.
*/
function yourprefix_register_main_options_metabox() {
/**
* Registers main options page menu item and form.
*/
$args = array(
'id' => 'yourprefix_main_options_page',
'title' => 'Main Options',
'object_types' => array( 'options-page' ),
'option_key' => 'yourprefix_main_options',
'tab_group' => 'yourprefix_main_options',
'tab_title' => 'Main',
);
// 'tab_group' property is supported in > 2.4.0.
if ( version_compare( CMB2_VERSION, '2.4.0' ) ) {
$args['display_cb'] = 'yourprefix_options_display_with_tabs';
}
$main_options = new_cmb2_box( $args );
/**
* Options fields ids only need
* to be unique within this box.
* Prefix is not needed.
*/
$main_options->add_field( array(
'name' => 'Site Background Color',
'desc' => 'field description (optional)',
'id' => 'bg_color',
'type' => 'colorpicker',
'default' => '#ffffff',
) );
/**
* Registers secondary options page, and set main item as parent.
*/
$args = array(
'id' => 'yourprefix_secondary_options_page',
'menu_title' => 'Secondary Options', // Use menu title, & not title to hide main h2.
'object_types' => array( 'options-page' ),
'option_key' => 'yourprefix_secondary_options',
'parent_slug' => 'yourprefix_main_options',
'tab_group' => 'yourprefix_main_options',
'tab_title' => 'Secondary',
);
// 'tab_group' property is supported in > 2.4.0.
if ( version_compare( CMB2_VERSION, '2.4.0' ) ) {
$args['display_cb'] = 'yourprefix_options_display_with_tabs';
}
$secondary_options = new_cmb2_box( $args );
$secondary_options->add_field( array(
'name' => 'Test Radio',
'desc' => 'field description (optional)',
'id' => 'radio',
'type' => 'radio',
'options' => array(
'option1' => 'Option One',
'option2' => 'Option Two',
'option3' => 'Option Three',
),
) );
/**
* Registers tertiary options page, and set main item as parent.
*/
$args = array(
'id' => 'yourprefix_tertiary_options_page',
'menu_title' => 'Tertiary Options', // Use menu title, & not title to hide main h2.
'object_types' => array( 'options-page' ),
'option_key' => 'yourprefix_tertiary_options',
'parent_slug' => 'yourprefix_main_options',
'tab_group' => 'yourprefix_main_options',
'tab_title' => 'Tertiary',
);
// 'tab_group' property is supported in > 2.4.0.
if ( version_compare( CMB2_VERSION, '2.4.0' ) ) {
$args['display_cb'] = 'yourprefix_options_display_with_tabs';
}
$tertiary_options = new_cmb2_box( $args );
$tertiary_options->add_field( array(
'name' => 'Test Text Area for Code',
'desc' => 'field description (optional)',
'id' => 'textarea_code',
'type' => 'textarea_code',
) );
}
add_action( 'cmb2_admin_init', 'yourprefix_register_main_options_metabox' );
/**
* A CMB2 options-page display callback override which adds tab navigation among
* CMB2 options pages which share this same display callback.
*
* #param CMB2_Options_Hookup $cmb_options The CMB2_Options_Hookup object.
*/
function yourprefix_options_display_with_tabs( $cmb_options ) {
$tabs = yourprefix_options_page_tabs( $cmb_options );
?>
<div class="wrap cmb2-options-page option-<?php echo $cmb_options->option_key; ?>">
<?php if ( get_admin_page_title() ) : ?>
<h2><?php echo wp_kses_post( get_admin_page_title() ); ?></h2>
<?php endif; ?>
<h2 class="nav-tab-wrapper">
<?php foreach ( $tabs as $option_key => $tab_title ) : ?>
<a class="nav-tab<?php if ( isset( $_GET['page'] ) && $option_key === $_GET['page'] ) : ?> nav-tab-active<?php endif; ?>" href="<?php menu_page_url( $option_key ); ?>"><?php echo wp_kses_post( $tab_title ); ?></a>
<?php endforeach; ?>
</h2>
<form class="cmb-form" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="POST" id="<?php echo $cmb_options->cmb->cmb_id; ?>" enctype="multipart/form-data" encoding="multipart/form-data">
<input type="hidden" name="action" value="<?php echo esc_attr( $cmb_options->option_key ); ?>">
<?php $cmb_options->options_page_metabox(); ?>
<?php submit_button( esc_attr( $cmb_options->cmb->prop( 'save_button' ) ), 'primary', 'submit-cmb' ); ?>
</form>
</div>
<?php
}
/**
* Gets navigation tabs array for CMB2 options pages which share the given
* display_cb param.
*
* #param CMB2_Options_Hookup $cmb_options The CMB2_Options_Hookup object.
*
* #return array Array of tab information.
*/
function yourprefix_options_page_tabs( $cmb_options ) {
$tab_group = $cmb_options->cmb->prop( 'tab_group' );
$tabs = array();
foreach ( CMB2_Boxes::get_all() as $cmb_id => $cmb ) {
if ( $tab_group === $cmb->prop( 'tab_group' ) ) {
$tabs[ $cmb->options_page_keys()[0] ] = $cmb->prop( 'tab_title' )
? $cmb->prop( 'tab_title' )
: $cmb->prop( 'title' );
}
}
return $tabs;
}
This works great, but I can't figure out how to actually get one of these values and display it in a theme. Anyone have an example?
You can use cmb2_get_option()
It takes 3 parameters: cmb2_get_option( $option_key, $field_id, $default );
So in your case:
$option_key = yourprefix_main_options,
$field_id = bg_color,
$default = the default value (in case you set it).
It should look like this:
cmb2_get_option( 'yourprefix_main_options', 'bg_color' );
cmb2_get_option( 'yourprefix_secondary_options', 'radio' );
and so on ..
Also, You can use your own function with Fallback:
/**
* Wrapper function around cmb2_get_option
* #since 0.1.0
* #param string $key Options array key
* #param mixed $default Optional default value
* #return mixed Option value
*/
function myprefix_get_option( $key = '', $default = false ) {
if ( function_exists( 'cmb2_get_option' ) ) {
// Use cmb2_get_option as it passes through some key filters.
return cmb2_get_option( 'yourprefix_main_options', $key, $default );
}
// Fallback to get_option if CMB2 is not loaded yet.
$opts = get_option( 'yourprefix_main_options', $default );
$val = $default;
if ( 'all' == $key ) {
$val = $opts;
} elseif ( is_array( $opts ) && array_key_exists( $key, $opts ) && false !== $opts[ $key ] ) {
$val = $opts[ $key ];
}
return $val;
}
Use it like this:
myprefix_get_option( bg_color )
Please use the following code :
get_option("<your id>");
Like :
get_option('bg_color');
Hope this will work for you.
You can try using array system with get_option() function.
First time you need to use get_option('your-option-key');
like your option-key is "yourprefix_main_options" so you need to use get_option('yourprefix_main_options');
then you can keep your value on variable. like
$main_option_data = get_option('yourprefix_main_options');
then you can use $main_option_data and your filed id as a array. like your one filed id is bg_color so you can use $main_option_data['bg_color'];
You can check my one previous work, I think it will be help you.
// Theme Options
add_action( 'cmb2_admin_init', 'mosc_panel_theme_options_metabox' );
/**
* Hook in and register a metabox to handle a theme options page and adds a menu item.
*/
function mosc_panel_theme_options_metabox() {
/**
* Registers options page menu item and form.
*/
$mos_option_panel = new_cmb2_box( array(
'id' => 'mosc_theme_options_page',
'title' => esc_html__( 'Theme Options', 'cmb2' ),
'parent_slug' => 'themes.php', // Make options page a submenu item of the themes menu.
'object_types' => array( 'options-page' ),
'option_key' => 'mosc_theme_options', // The option key and admin menu page slug.
'icon_url' => 'dashicons-palmtree', // Menu icon. Only applicable if 'parent_slug' is left empty.
) );
// Regular text field
$mos_option_panel->add_field( array(
'name' => __( 'Contact Form Heading', 'mosc' ),
'id' => 'mosc-contact-form-heading',
'type' => 'text',
'default' => __('Feel free to drop me a line', 'mosc'),
) );
}
then I've used this code for show my field value.
$mosc_contact_heading = get_option('mosc_theme_options');
if(!empty($mosc_contact_heading['mosc-contact-form-heading'])) {
echo esc_html($mosc_contact_heading['mosc-contact-form-heading']);
}
I've used this code to show my field value and working perfectly:
echo cmb2_get_option( '_key_options', 'text_text');

wp_query not filtering tax_query correctly in pre_get_posts

I'm having a problem with the following situation: I am creating a custom form for searching my custom post type (immobiliare) and attached to this I have 2 custom taxonomies: location and tipologia.
My searchform.php is:
<form role="search" method="get" id="searchform" action="<?php echo home_url( '/' ); ?>">
<input type="hidden" value="proceed" name="s" id="s" />
<fieldset>
<legend>Ricerca per:</legend>
<label class="screen-reader-text" for="query">Testo:</label>
<input type="text" value="<?php the_search_query(); ?>" name="query" id="query" />
</fieldset>
<fieldset>
<label class="screen-reader-text" for="s">Tipologia:</label>
<?php wp_dropdown_categories(array(
'hide_empty' => 0,
'taxonomy' => 'tipologia',
'name' => 'tipologia',
'show_option_all' => 'Nessuna Preferenza'
)); ?>
</fieldset>
<fieldset>
<label class="screen-reader-text" for="s">Località:</label>
<?php wp_dropdown_categories(array(
'hide_empty' => 0,
'taxonomy' => 'location',
'name' => 'location',
'show_option_all' => 'Nessuna Preferenza'
)); ?>
</fieldset>
<input type="submit" id="searchsubmit" value="Search" />
</form>
As you can see, I have 3 fields: 1 is a textfield and the other 2 are dropdowns with my taxonomies. I want the user to be able to search for these fields. I had to hack the "s" input type because it would not let me submit empty queries and added a "query" field instead.
My functions.php file is as follows:
<?php
// Start LOGGING
if(!function_exists('_log')){
function _log( $message ) {
if( WP_DEBUG === true ){
if( is_array( $message ) || is_object( $message ) ){
error_log( print_r( $message, true ) );
} else {
error_log( $message );
}
}
}
}
// end LOGGING
// start SEARCH FORM
function ij_get_int($var){
if (isset($var)) {
$int_var = intval($var);
if ($int_var > 0)
return $int_var;
}
return false;
}
function ij_get_str($var) {
$str_var = esc_attr($var);
if (strlen($str_var) > 0)
return $str_var;
return false;
}
function custom_search_results($query) {
if ($query->is_search && $query->is_main_query()) {
$tax_query = array(
'relation' => 'AND',
);
$location = ij_get_int($_GET['location']);
$tipologia = ij_get_int($_GET['tipologia']);
if ($location) {
array_push($tax_query, array(
'taxonomy' => 'location',
'field' => 'id',
'terms' => $location,
'operator' => 'IN'
));
}
if ($tipologia) {
array_push($tax_query, array(
'taxonomy' => 'tipologia',
'field' => 'id',
'terms' => $tipologia,
'operator' => 'IN'
));
}
$query->set('tax_query', $tax_query);
$query->set('s', ij_get_str($_GET['query']));
$query->set('post_type', 'immobiliare');
}
}
add_action('pre_get_posts', 'custom_search_results');
// end SEARCH FORM
?>
Here I hook into the response of my custom form and add:
The actual query ("query" and not "s"), when the user inputs valid data.
The filter by taxonomy, when needed.
I have no clue why this is not working out (spent a day!), I can see my query coming back with the correct 's' parameter:
$query->set('s', ij_get_str($_GET['query']));
but not the taxonomy filter.
What am I doing wrong? I want to use the standard Loop in my search.php file, so in some way I want my hook function to get automatically plugged into the loop. One curious thing is that if I create a new WP_Query object with the same setup (and not use the "set" method) it returns exactly what I want! I tried doing $query = new WP_Query... but this is not working too!!
If I dump the query request on the top of my search.php I get the following:
SELECT SQL_CALC_FOUND_ROWS wp_posts.* FROM wp_posts WHERE 1=1 AND 0 = 1 AND (((wp_posts.post_title LIKE '%vil%') OR (wp_posts.post_content LIKE '%vil%'))) AND wp_posts.post_type = 'immobiliare' AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private') GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 10
Does anyone have any hints to share? You would be really cool to give me a hand!
Thanks
Dan
You probably solved this by now, but your query has ... where 1=1 and 0=1 ... so it wouldn't return anything since you are asking for a record set of items both true and false.

Resources