I'm trying to create a widget that enables user to select which categories will be displayed.
The following is piece of codes I created but the changes of the checkbox state can't be saved. There are only two values : the title and list of selected categories.
function form($instance) {
$instance = (array)$instance;
if( empty($instance['title']) ) $instance['title'] = 'Category';
$selected_categories = (array)$instance['category'];
var_dump($selected_categories);
....
$categories = get_categories( array('exclude'=> 1) );
foreach($categories as $category) : ?>
<div>
<input type="checkbox" name="<?php echo $this->get_field_name('category'); ?>"
value="<?php echo $category->cat_ID; ?>"
<?php echo $category->cat_name; ?>
</div>
<?php endforeach; ?>
}
function update($new_instance, $old_instance) {
$instance = $old_instance;
$instance['title'] = strip_tags($new_instance['title']);
$instance['category'] = $new_instance['category'];
return $instance;
}
I observe the changes through var_dump($selected_categories). The value is always array(size=0) ignoring how many checkbox I checked.
I have no idea how to passing array in $instance variable.
Thanks in advance.
Do you have a validation function that fills the values in the array if they are not set? That is the »update« method of the widget. Perhaps you should add:
'<input name="..." value="..." id="'.$this->get_field_id( 'category' ).'" />';
to your input element.
I spent a lot of time on this exact issue. Searches online on this topic were less than satisfying. I wanted to understand how the Widget extends WP_Widget object works. Like the original post I too wanted to allow my admins to select from a dynamic check list of all post categories. In my website, I'm using this for promos, and I expect to have lots of instances of this puppy. A robust instance storage system is essential for me.
A couple of stupid questions that were bugging me.
1) What's up with the funky label for=.... Category Name /label things I see on each and every example online. (Note 'label' is surrounded by left/right symbols.. can't do that here..) Is that required, or merely somebody copying what's been done before (within the file defaults-widgets.php in the WordPress source code)? Ans: total waste of time. Less is more, code it right.
2) I really really wanted to understand the mechanism of how the system saves a users selections. There appears to be no obvious coding on the backend page to capture the selections. I spent a long time here searching, including attempting to step thru the code on a debugger, with lousy results. I spent a lot of time with var_dump($instance) to understand results. The system works, but I don't really understand why.
My logic in making this system work was to create a single checkbox variable, get that to work. Next step was to create an array of checkbox variables but only use one of them and get that to work. Finally utilize the entire array of checkbox variables. Success.
Code extract follows:
/*Saves the settings. */
function update( $new_instance, $old_instance ){
$args = array(
//your selections here.
);
$categories = get_categories( $args ); // returns an array of category objects
$arrlength=count($categories);
for($x=0;$x<$arrlength;$x++){
$tempArray[$categories[$x]->slug] = '';
}
$instance = $old_instance;
$new_instance = wp_parse_args( (array) $new_instance, $tempArray );
for($x=0;$x<$arrlength;$x++){
$instance[$categories[$x]->slug] = $new_instance[$categories[$x]->slug] ? 1 : 0;
}
return $instance;
}
/*Creates the form for the widget in the admin back-end. */
function form( $instance ){
echo '<p>Choose your categories of interest. Multiple selections are fine.</p> ';
$args = array(
//your selections here. Use same args as update function, duh.
);
$categories = get_categories( $args ); // returns an array of category objects
$arrlength=count($categories);
for($x=0;$x<$arrlength;$x++){
$tempArray[$this->get_field_id($categories[$x]->slug)] = '';
}
$instance = wp_parse_args( (array) $instance, $tempArray );
for($x=0;$x<$arrlength;$x++){
$tempCheckFlag[$categories[$x]->slug] = $instance[$categories[$x]->slug] ? 'checked="checked"' : '';
// could also use 'checked()' function
// Yup, this could be combined with the for loop below,
// listed here seperately to enhance understanding of what's going on.
}
for($x=0;$x<$arrlength;$x++)
{
echo '<p><input class ="checkbox" type="checkbox" value="1" id="'.$this->get_field_id($categories[$x]->slug).'" name="'.$this->get_field_name($categories[$x]->slug).'"'.$tempCheckFlag[$categories[$x]->slug].'>'.$categories[$x]->name.' (Category # '.$categories[$x]->term_id.' )</p>';
}
}
When I need to use the selections in my widget function, I retrieve the admin's selections from the $instance variable.
/* Displays the Widget in the front-end */
function widget( $args, $instance ){
//....
foreach($instance as $key=>$value)
{
if ($value){
$category_array[]=$key;
}
}
// Now I have a simple array of just those categories that had a check mark...
Here is a second solution that uses an array of checkbox.
I solved this problem with a checkbox array in the new version 1.8 of my widget recently updated posts widget.
I use the second form of foreach
foreach (array_expression as $key => $value).
$key allows to obtain a unique id for each checkbox.
Here $id is a number incremented by the foreach itself.
function form($instance) {
$term_taxonomy_id = (isset($instance['term_taxonomy_id']) ? array_map('absint', $instance['term_taxonomy_id']) : array("0"));
<?php
$categ = get_categories();
foreach($categ as $id => $item) :
?>
<br/>
<input type="checkbox"
id="<?php echo $this->get_field_id('term_taxonomy_id') . $id; ?>"
name="<?php echo $this->get_field_name('term_taxonomy_id'); ?>[]"
<?php if (isset($item->term_taxonomy_id)) {
if (in_array($item->term_taxonomy_id,$term_taxonomy_id))
echo 'checked';
};
?>
value="<?php echo $item->term_taxonomy_id; ?>" />
<label for="<?php echo $this->get_field_id('term_taxonomy_id') . $id; ?>" >
<?php echo $item->name ?>
</label>
<?php endforeach; ?>
I stored term_taxonomy_id instead cat_ID, for my plugin, but you can pretty much store cat_ID, it will work as well.
The array data is sanitized by the php function array_map ().The update function is:
function update($new_instance, $old_instance) {
// Par défaut, aucune catégorie n'est exclue
$instance['term_taxonomy_id'] = (isset($new_instance['term_taxonomy_id']) ? array_map( 'absint', $new_instance['term_taxonomy_id']) : array('0'));
For their use in a MySQL query, I implodes it into a set of values:
// écriture de la liste des objects sélectionnées en langage MySQL
if (isset($instance['term_taxonomy_id']))
$selected_object = "('".implode(array_map( 'absint',$instance['term_taxonomy_id']),"','")."')";
else $selected_object = "('0')";