Wordpress Settings API error - wordpress

Hi I am trying to creating some custom options for a template I am developing but I seem to be getting an error:
Warning: Illegal string offset 'show_header' in C:\xampp\htdocs\wordpress\wp-content\themes\01MyWork\includes\theme-options.php on line 62
This is the line that seems to be throwing the error:
$html = '<input type="checkbox" id="show_header" name="thanathos_theme_display_options[show_header]" value="1" ' . checked(1, $options['show_header'], false) . '/>';
And this is the entire code:
<?php
function thanatos_theme_menu(){
add_theme_page(
"Thanathos Theme Options",
"Thanathos Theme",
"administrator",
"thanathos_theme_options",
"thanathos_theme_display_callback"
);
}
add_action('admin_menu' , 'thanatos_theme_menu');
function thanathos_theme_display_callback(){
?>
<div class="wrap">
<div id="icon-themes" class="icon32"></div>
<h2>Sandbox Theme Options</h2>
<?php settings_errors(); ?>
<!--Create the form that will be used to render our options-->
<form method="post" action="options.php">
<?php settings_fields('thanathos_theme_display_options'); ?>
<?php do_settings_sections( 'thanathos_theme_display_options' ); ?>
<?php submit_button(); ?>
</form>
</div>
<?php
}
add_action('admin_init' , 'thanatos_initializa_theme_options');
function thanatos_initializa_theme_options(){
if( false == get_option( 'thanathos_theme_display_options' ) ) {
add_option( 'thanathos_theme_display_options' );
}
add_settings_section(
'general_settings_section',
'Thanatos Options',
'thanatos_general_options_callback',
'thanathos_theme_display_options'
);
add_settings_field(
'show_header',
'Header',
'thanathos_field_header_callback',
'thanathos_theme_display_options',
'general_settings_section',
array( // The array of arguments to pass to the callback. In this case, just a description.
'Activate this setting to display the header.'
)
);
register_setting('thanathos_theme_display_options', 'thanathos_theme_display_options');
}
function thanatos_general_options_callback(){
echo 'mergem la mare';
}
function thanathos_field_header_callback($args){
// First, we read the options collection
$options = get_option('thanathos_theme_display_options');
// Next, we update the name attribute to access this element's ID in the context of the display options array
// We also access the show_header element of the options collection in the call to the checked() helper function
$html = '<input type="checkbox" id="show_header" name="thanathos_theme_display_options[show_header]" value="1" ' . checked(1, $options['show_header'], false) . '/>';
// Here, we'll take the first argument of the array and add it to a label next to the checkbox
$html .= '<label for="show_header"> ' . $args[0] . '</label>';
echo $html;
}
?>

Yes, that's the problematic part:
if( false == get_option( 'thanathos_theme_display_options' ) ) {
add_option( 'thanathos_theme_display_options' );
}
That's the initial if statement at the beginning of the thanatos_initializa_theme_options() function.
You can find the solution in the very neat Theme Options API tut at http://wp.tutsplus.com/tutorials/theme-development/the-complete-guide-to-the-wordpress-settings-api-part-4-on-theme-options/#post-684925289
Or, more exactly more exactly in this article's comments section.
I'm pasting the Steve Bondy's smart solution here because for some reason making the page scroll to the appropriate comment doesn't work for me (in Chrome at least).
START quote
(...)One little issue I had - I followed along through reordering the code, up to just before adding the Social options. At that point I discovered that the code was broken. I would get an error like
Warning: Illegal string offset 'show_header' in ...\themes\Sandbox\functions.php
Warning: Illegal string offset 'show_content' in ...\themes\Sandbox\functions.php
Warning: Illegal string offset 'show_footer' in ...\themes\Sandbox\functions.php
It turns out that this error was caused by adding 'sandbox_theme_display_options' to the options table without giving it a value. If you change sandbox_initialize_theme_options as follows it will create and initialize the options, avoiding the error experienced by myself and others.
function sandbox_initialize_theme_options() {
// If the theme options don't exist, create them.
if( false == get_option( 'sandbox_theme_display_options' ) ) {
$options = array("show_header" => TRUE, "show_content" => TRUE, "show_footer" => TRUE);
add_option( 'sandbox_theme_display_options', $options);
} // end if
(...)
If the old code has been run the empty 'sandbox_theme_display_options' value must be deleted from the database first. Alternatively, the following code will also detect this case and correct it.
function sandbox_initialize_theme_options() {
// See if the options exist, and initialize them if they don't
$options = get_option( 'sandbox_theme_display_options' );
if( false == $options or $options == "" ) {
$options = array("show_header" => TRUE, "show_content" => TRUE, "show_footer" => TRUE);
update_option( 'sandbox_theme_display_options', $options);
} // end if
(...)
This checks for non-existant or empty options values and initializes the options using update_option instead of add_option.
EOF quote

You are using name="thanathos_theme_display_options[show_header]" in plain HTML. Probably you want to parse by PHP the string [show_header].

You may have to run:
delete_option('thanathos_theme_display_options');
during 'admin_init' if you think you have old plugin information mucking about in the database and need a fresh start.

Related

wordpress: Display last record of Custom post type on home page

I am a novice developer of WordPress.
I created a custom post type wp_locations to practice.
It has three numeric fields that are entered as <input type="number">: a phone_number; a fax_number and a zip_code
$wp_location_phone = get_post_meta($post->ID,'wp_location_phone',true);
$wp_location_fax = get_post_meta($post->ID,'wp_location_fax',true);
$wp_location_zipcode = get_post_meta($post->ID,'wp_location_zipcode',true);
That works properly and stores the information.
I have a plugin to create the Custom Post Type and save a new record in WordPress.
Now I want to display this record on the home page in a table.
I searched but I could not run any suggestions. Please guide me with an example. Thanks
class wp_simple_location{
private $wp_location_trading_hour_days = array();
public function __construct(){
add_action('init', array($this,'set_location_trading_hour_days')); //sets the default trading hour days (used by the content type)
add_action('init', array($this,'register_location_content_type'));
add_action('add_meta_boxes', array($this,'add_location_meta_boxes'));
add_action('save_post_wp_locations', array($this,'save_location')); //save location
register_activation_hook(__FILE__, array($this,'plugin_activate'));
register_deactivation_hook(__FILE__, array($this,'plugin_deactivate'));
}
//display function used for our custom location meta box*/
public function location_meta_box_display($post){
wp_nonce_field('wp_location_nonce', 'wp_location_nonce_field');
//collect variables
$wp_location_phone = get_post_meta($post->ID,'wp_location_phone',true);
$wp_location_fax = get_post_meta($post->ID,'wp_location_fax',true);
$wp_location_zipcode = get_post_meta($post->ID,'wp_location_zipcode',true);
/*
// information is gathered here in a form. The relevant inputs are:
<input type="number" name="wp_location_phone" id="wp_location_phone" value=" <?php echo $wp_location_phone;"?> />
<input type="number" name="wp_location_fax" id="wp_location_fax" value=" <?php echo $wp_location_fax; ?>"/>
<input type="number" name="wp_location_zipcode" id="wp_location_zipcode" value=" <?php echo $wp_location_zipcode;" ?> />
*/
}
//triggered when adding or editing a location
public function save_location($post_id){
// nonce & autosave checks removed from example as they are irrelevant
//get our phone, email and address fields
$wp_location_phone = isset($_POST['wp_location_phone']) ? sanitize_text_field($_POST['wp_location_phone']) : '';
$wp_location_fax = isset($_POST['wp_location_fax']) ? sanitize_text_field($_POST['wp_location_fax']) : '';
$wp_location_zipcode = isset($_POST['wp_location_zipcode']) ? sanitize_text_field($_POST['wp_location_zipcode']) : '';
//update phone, email and address fields
update_post_meta($post_id, 'wp_location_phone', $wp_location_phone);
update_post_meta($post_id, 'wp_location_fax', $wp_location_fax);
update_post_meta($post_id, 'wp_location_zipcode', $wp_location_zipcode);
//search for our trading hour data and update
foreach($_POST as $key => $value){
//if we found our trading hour data, update it
if(preg_match('/^wp_location_trading_hours_/', $key)){
update_post_meta($post_id, $key, $value);
}
}
do_action('wp_location_admin_save',$post_id);
}
} // end class
Other notes:
The customer post type name is "wp_location" but the slug is "locations":
$args = array(
[...]
'rewrite' => array('slug' => 'locations', 'with_front' => 'true')
);
register_post_type('wp_locations', $args);
A quick Google search for "wp_simple_location" shows that you have taken this example from SitePoint and changed it.
Based on that, I'm going to amend the rest of that example to show you how to create a shortcode you can use.
Assumptions:
I presume the code you posts isn't your from your test site, as it is
not valid (e.g. you are missing many )
I'm also going to assume that you only have 1 location - the
sitepoint example allowed you add many but you appear to have removed
that code
Code:
1. Add back in the get_locations_output function.
You deleted the get_locations_output function, which is how you actually display the information - which is what you want! So you need to add it back into your wp_simple_location class. I have changed it so it should work with your changes
// main function for displaying locations (used for our shortcodes and widgets)
public function get_locations_output(){
//find locations
$location_args = array(
'post_type' => 'wp_locations',
'posts_per_page'=> 999,
'post_status' => 'publish'
);
//output
$html = '';
$locations = get_posts($location_args);
//if we have a location it will be returned in an array, so loop through it
if($locations){
$html .= '<article class="location_list cf">';
//foreach location
foreach($locations as $location){
$html .= '<section class="location">';
//collect location data
$wp_location_id = $location->ID;
$wp_location_phone = get_post_meta($wp_location_id,'wp_location_phone',true);
$wp_location_fax= get_post_meta($wp_location_id,'wp_location_fax',true);
$wp_location_zipcode= get_post_meta($wp_location_id,'wp_location_zipcode',true);
// output details only if any were entered
if($wp_location_phone || $wp_location_fax || $wp_location_zipcode){
$html .= '<table>';
if(!empty($wp_location_phone)){
$html .= '<tr><td>Phone: </td><td>' . $wp_location_phone . '</td></tr>';
}
if(!empty($wp_location_fax)){
$html .= '<tr><td>Fax: </td><td>' . $wp_location_fax. '</td></tr>';
}
if(!empty($wp_location_zipcode)){
$html .= '<tr><td>Zipcode: </td><td>' . $wp_location_zipcode. '</td></tr>';
}
$html .= '</table>';
}
//apply the filter after the main content, before it ends
//(lets third parties hook into the HTML output to output data)
$html = apply_filters('wp_location_after_main_content', $html);
$html .= '</section>';
}
$html .= '</article>';
}
return $html;
} // end function
**2. Create a new class that adds a shortcode to let you include the information in pages **
Note: Proper practice is create the new new class in a separate php file and include it in your wp_simple_location class file, but to keep this example simple, add this to the bottom of the file containing your wp_simple_location class:
class wp_location_shortcode{
//on initialize
public function __construct(){
add_action('init', array($this,'register_location_shortcodes')); //shortcodes
}
//location shortcode
public function register_location_shortcodes(){
add_shortcode('wp_locations', array($this,'location_shortcode_output'));
}
//shortcode display
public function location_shortcode_output($atts, $content = '', $tag){
//get the global wp_simple_locations class
global $wp_simple_locations;
//uses the main output function of the location class
$html = $wp_simple_locations->get_locations_output();
return $html;
}
}
$wp_location_shortcode = new wp_location_shortcode;
**3. Use the shortcode to include the information **
To include the information in any page, you just need to use the following shortcode in the post editor:
[wp_locations]
Note:
You should also clean up your plugin code - for example the code starting //search for our trading hour data and update is not needed as you deleted the hours from the plugin. Also make sure all your php tags are correct!
As I mentioned, I have just changed the SitePoint example to work with your changes, so I haven't tested any of this. If you have any questions it might be a good idea to re-read the SitePoint tutorial because it explains the code in detail.

Saving add_meta_box data to multiple post_types

I have the following code to create and save custom meta boxes within my Wordpress site. This solution works fine for my 'work' post_type, but will not save on a standard 'post'. The meta boxes appear fine on both post_types, but will only save on 'work'. Therefore I believe the issue lies within the save function, but I cannot decipher any reason why this works on only the one post_type?
I have pared the below code down to what I believe is the essential code.
Thanks.
// Allow registering of custom meta boxes
add_action( 'add_meta_boxes', 'add_custom_metaboxes' );
// Register the Project Meta Boxes
function add_custom_metaboxes() {
$post_types = array ( 'post', 'work' );
foreach( $post_types as $post_type )
{
add_meta_box('xx_introduction', 'Introduction', 'xx_introduction', $post_type, 'normal', 'high');
add_meta_box('xx_more', 'More', 'xx_more', 'work', 'normal', 'high');
}
}
// Add Introduction Metabox
function xx_introduction() {
global $post;
// Noncename needed to verify where the data originated
echo '<input type="hidden" name="introductionmeta_noncename" id="introductionmeta_noncename" value="' .
wp_create_nonce( plugin_basename(__FILE__) ) . '" />';
// Get the introduction data if its already been entered
$introduction = get_post_meta($post->ID, '_introduction', true);
// Echo out the field
echo '<textarea name="_introduction" class="widefat" rows="5">' . $introduction . '</textarea>';
}
// Add More Metabox
function xx_more() {
global $post;
// Noncename needed to verify where the data originated
echo '<input type="hidden" name="moremeta_noncename" id="moremeta_noncename" value="' .
wp_create_nonce( plugin_basename(__FILE__) ) . '" />';
// Get the more data if its already been entered
$more = get_post_meta($post->ID, '_more', true);
// Echo out the field
echo '<textarea name="_more" class="widefat" rows="5">' . $more . '</textarea>';
}
// Save the Metabox Data
function xx_save_custom_meta($post_id, $post) {
// verify this came from the our screen and with proper authorization,
// because save_post can be triggered at other times
if ( !wp_verify_nonce( $_POST['introductionmeta_noncename'], plugin_basename(__FILE__) )) {
return $post->ID;
}
}
// Is the user allowed to edit the post or page?
if ( !current_user_can( 'edit_post', $post->ID ))
return $post->ID;
// OK, we're authenticated: we need to find and save the data
// We'll put it into an array to make it easier to loop though.
$introduction_meta['_introduction'] = $_POST['_introduction'];
$more_meta['_more'] = $_POST['_more'];
// Add values of $introduction_meta as custom fields
foreach ($introduction_meta as $key => $value) { // Cycle through the $testimonial_meta array
if( $post->post_type == 'revision' ) return; // Don't store custom data twice
$value = implode(',', (array)$value); // If $value is an array, make it a CSV (unlikely)
if(get_post_meta($post->ID, $key, FALSE)) { // If the custom field already has a value
update_post_meta($post->ID, $key, $value);
} else { // If the custom field doesn't have a value
add_post_meta($post->ID, $key, $value);
}
if(!$value) delete_post_meta($post->ID, $key); // Delete if blank
}
}
// Add values of $more_meta as custom fields
foreach ($more_meta as $key => $value) { // Cycle through the $more_meta array
if( $post->post_type == 'revision' ) return; // Don't store custom data twice
$value = implode(',', (array)$value); // If $value is an array, make it a CSV (unlikely)
if(get_post_meta($post->ID, $key, FALSE)) { // If the custom field already has a value
update_post_meta($post->ID, $key, $value);
} else { // If the custom field doesn't have a value
add_post_meta($post->ID, $key, $value);
}
if(!$value) delete_post_meta($post->ID, $key); // Delete if blank
}
}
add_action('save_post', 'xx_save_custom_meta', 1, 2); // save the custom fields
Having experimented with this for a couple of days, I have a semi solution to the issue I was experiencing. In the original code, I was attempting to register three meta boxes, but placing two of them in multiple post types ($post_type) and the other in just a single post type (work). I have not determined the cause, but this is what was causing the meta data not to save in one of the post types.
Whilst this isn't a full answer with a detailed breakdown, it at least locates the source of the issue, and my initial thought that the issue lies within the save function is correct, I just don't know how to fix this myself. This solution works fine for me however so I won't be investing anymore time into this issue.
Hopefully this is of use to others at least as a starting point.
// Register the Project Meta Boxes
function add_custom_metaboxes() {
$post_types = array ( 'post', 'work' );
foreach( $post_types as $post_type )
{
add_meta_box('xx_introduction', 'Introduction', 'xx_introduction', $post_type, 'normal', 'high');
add_meta_box('xx_more', 'Introduction', 'xx_introduction', $post_type, 'normal', 'high');
}
}

How to add placeholder in buddypress registration ? How to make field description as input placeholder?

How to add placeholder in buddypress registration?
Can we use field description as placeholder for input field?
In register.php under bp-template.These two lines of code make xprofile
$field_type = bp_xprofile_create_field_type( bp_get_the_profile_field_type() );
$field_type->edit_field_html();
How to edit them.Where these lines are connected.How to edit x-profile field.
Or even better yet, combining these two answers. Simply add this to your functions.php:
function wp_add_placeholder($elements){
$elements['placeholder'] = bp_get_the_profile_field_name();
return $elements;
}
add_action('bp_xprofile_field_edit_html_elements','wp_add_placeholder');
There is always a better way to do it then editing the core:
function wp_add_placeholder($elements){
$elements['placeholder'] = 'Placeholder';
return $elements;
}
add_action('bp_xprofile_field_edit_html_elements','wp_add_placeholder');
just struggled with this issue and fastest thing i came up were override classes that handles different fields:
First you need to find class named BP_XProfile_Field_Type_Textbox (for textbox). In bp v2.0.2 it can be found on bp-xprofile/bp-xprofile-class.php:2358. Copy whole class in your functions and rename class name as you desire. let's say i renamed it as CUSTOM_BP_XProfile_Field_Type_Textbox. Inside this class there are function called public function edit_field_html( array $raw_properties = array() ).
Replace:
$html = $this->get_edit_field_html_elements( array_merge(
array(
'type' => 'text',
'value' => bp_get_the_profile_field_edit_value(),
),
$raw_properties
) );
?>
<label for="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php esc_html_e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
<?php do_action( bp_get_the_profile_field_errors_action() ); ?>
<input <?php echo $html; ?>>
<?php
}
With that:
$required = bp_get_the_profile_field_is_required() ? ' ' . esc_html__( '(required)', 'buddypress' ) : '';
$html = $this->get_edit_field_html_elements( array_merge(
array(
'type' => 'text',
'value' => bp_get_the_profile_field_edit_value(),
'placeholder' => bp_get_the_profile_field_name() . $required
),
$raw_properties
) );
?>
<?php do_action( bp_get_the_profile_field_errors_action() ); ?>
<input <?php echo $html; ?>>
<?php
}
Next thing you need to do is override function that hendles field classes. Copy function called bp_xprofile_get_field_types into your theme and rename it. let's say i renamed it as custom_bp_xprofile_get_field_types.
In fields array rename 'textbox' value from BP_XProfile_Field_Type_Textbox to CUSTOM_BP_XProfile_Field_Type_Textbox (the class you created and modified).
Finl thing you need to do is override function that print final result. Copy function called bp_xprofile_create_field_type into your theme and rename it. let's say i renamed it as custom_bp_xprofile_create_field_type.
In this function replace:
$field = bp_xprofile_get_field_types();
with:
$field = custom_bp_xprofile_get_field_types();
to use your modified field output
In register.php use just created new function instead of original buddypresses one so the final result will be:
$field_type = custom_bp_xprofile_create_field_type( bp_get_the_profile_field_type() );
$field_type->edit_field_html();
It is good to copy register.php to YOUR_THEME/buddypress/members/register.php to not lose your changes after updating the bp plugin.
If you like to modify other fields just rename field's class in classes array in custom_bp_xprofile_get_field_types and copy bp's class of that field and rename it as in fields array.
Hope that helps. There might be better way, but i didn't find any.

Wordpress user profile display name - change from selectbox to textbox

Im trying to change the user profile "Display name publicly as" from a select box to a textbox. Any ideas on how this can be done? Couldnt find anything all all.
Two way to solve it. You edit the wordpress core file, which is not a good way. Or you can add an extra field on profile box using wordpress hook.
I am giving you the first way:
Go to wp-admin/user-edit.php
Open the file. Then find
<td>
<select name="display_name" id="display_name">
<?php
$public_display = array();
$public_display['display_nickname'] = $profileuser->nickname;
$public_display['display_username'] = $profileuser->user_login;
if ( !empty($profileuser->first_name) )
$public_display['display_firstname'] = $profileuser->first_name;
if ( !empty($profileuser->last_name) )
$public_display['display_lastname'] = $profileuser->last_name;
if ( !empty($profileuser->first_name) && !empty($profileuser->last_name) ) {
$public_display['display_firstlast'] = $profileuser->first_name . ' ' . $profileuser->last_name;
$public_display['display_lastfirst'] = $profileuser->last_name . ' ' . $profileuser->first_name;
}
if ( !in_array( $profileuser->display_name, $public_display ) ) // Only add this if it isn't duplicated elsewhere
$public_display = array( 'display_displayname' => $profileuser->display_name ) + $public_display;
$public_display = array_map( 'trim', $public_display );
$public_display = array_unique( $public_display );
foreach ( $public_display as $id => $item ) {
?>
<option id="<?php echo $id; ?>"<?php selected( $profileuser->display_name, $item ); ?>><?php echo $item; ?></option>
<?php
}
?>
</select>
</td>
Change it with
<th><label for="display_name"><?php _e('Display name publicly as'); ?> </label></th>
<td><input type="text" name="display_name" id="display_name" value="<?php echo esc_attr( $profileuser->display_name ); ?>" class="regular-text" /></td>
But still this is not a good solution.
I came across this same issue and used a bit of javascript to solve it. Wordpress allows you to set the display_name field to anything you want, so you can use the following script (in your theme's functions.php file) to convert the select to a text field.
function change_display_name_to_textfield() {
echo "><div>"; // don't remove '>'
?>
<script>
jQuery(function($) {
// replace display_name select with input
$('select#display_name').after( '<input type="text" name="display_name" id="display_name" value="' + $('#display_name').val() + '" class="regular-text">' ).remove();
})
</script>
<?php
echo "</div"; // don't add '>'
}
// hook into new user and edit user pages
add_action( "user_new_form_tag", "change_display_name_to_textfield" );
add_action( "user_edit_form_tag", "change_display_name_to_textfield" );
Note the weird use of opening/closing tags. This is because those particular hooks execute just before the end of the opening form tag. So you need to close the form tag, print your script, then print a final tag without closing it.
For admin user edit pages, I found one of the easiest way:
add_action( 'personal_options', 'rm_personal_options' );
function rm_personal_options($profileuser){
if( !is_admin() ) return; ?>
<script type="text/javascript">
jQuery(document).ready(function($){
//$("input#nickname").parent().parent().hide();
$("select#display_name").replaceWith(function(){
return '<input type="text" name="display_name" id="display_name" value="'+$(this).val()+'" class="regular-text" style="width:25em" />';
});
});
</script>
<?php
}
Simply paste it into the functions.php of the theme file :)

Checkbox array in Wordpress widget?

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')";

Resources