Better way to handle WordPress Dashboard widgets with options

On the previous week I published the tutorial about creating and removing custom dashboard widgets for WordPress Multisite install. I decided to continue with this topic and to publish more rad stuff on it.

This tutorial was inspired by an example that I found on official WordPress Codex documentation here. Once I tried that example on my own website, I decided that it is far away from perfect.

Let me guide though two steps of creating a dashboard widget with options and modifying it.

Step 1. Begin with creating a default WordPress Dashboard Widget with options

As I already said above, it is the simplified example from WP Codex. You can insert it to your current theme functions.php file (but better – in child theme or custom plugin).

add_action( 'wp_dashboard_setup', 'prefix_add_dashboard_widget' );
 
function prefix_add_dashboard_widget() {
	wp_add_dashboard_widget(
		'misha_dashboard_widget', // widget ID
		'Custom Dashboard Widget', // widget title
		'misha_dashboard_widget', // callback #1 to display it
		'misha_process_my_dashboard_widget' // callback #2 for settings
	);
}
/*
 * Callback #1 function
 * Displays widget content
 */
function misha_dashboard_widget() {
 
	// if the widget is configured and the post is exists
	if( $post = get_post( get_option( 'custom_post' ) ) ) {
		$c = do_shortcode( html_entity_decode( $post->post_content ) );
		echo "<h2>{$post->post_title}</h2><p>{$c}</p>";
	} else {
		echo 'Widget is not configured.';
	}
 
}
 
/*
 * Callback #2 function
 * This function displays your widget settings
 */
function misha_process_my_dashboard_widget() {
 
	// basic checks and save the widget settings here
	if( 'POST' == $_SERVER['REQUEST_METHOD'] 
	 && isset( $_POST['my_custom_post'] ) ) {
		update_option( 'custom_post', absint($_POST['my_custom_post']) );
	}
 
	echo '<h3>Select a page that will be displayed in this widget</h3>'
	. wp_dropdown_pages( array(
		'post_type' => 'page',
		'selected' => get_option( 'custom_post' ),
		'name' => 'my_custom_post',
		'id' => 'my_custom_post',
		'show_option_none' => '- Select -',
		'echo' => false
	) );
 
}

Step 1 can work standalone, so you do not need to implement the second step which is all about AJAX. Here is how it works.

Custom WordPress Dashboard Widget with Options
The page refreshes every time I click the Configure link or save the changes.

Step 2. Make it AJAX

If you would like your widget to work more smoothly, you must consider implementing this step too (you can scroll down first to look at the demo).

2.1 Some CSS for slick opacity animation

If you add this code, the “Configure” button will appear more smoothly. No reason to create a separate CSS file for it, so I recommend to add it via admin_head action hook.

.edit-box.open-box{
	transition: opacity .2s;
}

2.2 jQuery code to process asynchronous requests

As for JavaScript code below, it is better to connect it to your admin area with a separate .js file and admin_enqueue_scripts action hook. But admin_head is also ok.

Please note, that #misha_dashboard_widget is your widget ID that we set in Step 1, line 5.

jQuery(function($){
 
	// the Configure link click event
	$('#misha_dashboard_widget .edit-box.open-box').click(function(){
		var button = $(this);
		$.ajax({
			url: ajaxurl, // it is predefined in /wp-admin/
			type: 'POST',
			data: 'action=showform',
			beforeSend : function( xhr ){
				// add preloader
				button.hide().before('<span class="spinner" style="visibility:visible;display:block;margin:0 0 0 15px"></span>');
			},
			success : function( data ){
				// remove preloader
				button.prev().remove();
				// insert settings form
				$('#misha_dashboard_widget').find('.inside').html(data);
			}
 
		});
		return false;
	});
 
	// form submit event
	$('body').on('submit', '#misha_widget_settings', function(){
		var form = $(this);
		$.ajax({
			url: ajaxurl,
			type: 'POST',
			data: $(this).serialize(), // all form fields
			beforeSend : function( xhr ){
				// add preloader just after the submit button
				form.find('.submit').append('<span class="spinner" style="display:inline-block;float:none;visibility:visible;margin:0 0 0 15px"></span>');
			},
			success : function( data ){
				$('#misha_dashboard_widget').find('.inside').html(data);
				// show the Configure link again
				$('#misha_dashboard_widget .edit-box.open-box').show();
			}
		});
		return false;
	});
});

Do not forget to check that no errors have appeared in your browser console.

2.3 Process AJAX requests in PHP

Insert the below code in the same place where you inserted the code from Step 1. Some notes:

/*
 * This action hook shows settings form
 */
add_action( 'wp_ajax_showform', 'misha_ajax_show_form' ); // wp_ajax_{ACTION}
function misha_ajax_show_form(){
 
	// widget ID should match but it is not required
	$widget_id = 'misha_dashboard_widget';
 
	echo '<form method="post" id="misha_widget_settings">
	<h3>Select a page that will be displayed in widget</h3>'
	. wp_dropdown_pages( array(
		'post_type' => 'page',
		'selected' => get_option( 'custom_post' ),
		'name' => 'my_custom_post',
		'id' => 'my_custom_post',
		'show_option_none' => '- Select -',
		'echo' => false
	) )
	. '<input type="hidden" name="action" value="widgetsave" /><input type="hidden" name="widget_id" value="' . $widget_id . '">'
	. wp_nonce_field( 'edit-dashboard-widget_' . $widget_id, 'dashboard-widget-nonce', true, false )
	. '<p class="submit"><input type="submit" name="submit" id="submit" style="display:inline-block" class="button button-primary" value="Submit"></p></form>';
 
	die;
}
 
/*
 * This action hook saves the settings and displays the widget content
 */
add_action( 'wp_ajax_widgetsave', 'misha_save_widget' ); // wp_ajax_{ACTION}
function misha_save_widget(){
 
	// security check
	check_ajax_referer( 'edit-dashboard-widget_' . $_POST['widget_id'], 'dashboard-widget-nonce' );
 
	$post_id = absint( $_POST['my_custom_post'] );
 
	update_option( 'custom_post', $post_id );
 
	if( $post = get_post( $post_id ) ) {
		$c = do_shortcode( html_entity_decode( $post->post_content ) );
		echo "<h2>{$post->post_title}</h2><p>{$c}</p>";
	} else {
		echo 'Widget is not configured.';
	}
 
	die;
}

Here is the result:

Related

Need some help with WordPress?

If you need some professional developer help, I will be happy to assist you.

Contact me Who I am?

Leave a comment

php js HTML CSS Code