Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

How do I create a widget that only allows a single instance of a widget to be added through the Wordpress interface?

The default behaviour of widgets allows multiple instances to be added.

I am using the Example code from http://codex.wordpress.org/Widgets_API

I have seen a similar question where the answer was to use the old widget code, but I would like to continue to use that more modern code if possible.

I have seen plugins such as Twitter for Wordpress that give exact control over the number of instances allowed.

Thanks,
matt

share|improve this question

3 Answers 3

Switch after the 1st instance and abort

In the following example you can find a static variable that's not set on the first instance. If the widget gets called the 1st time, we set it to true. On the 2nd run, we abort and just return without actually serving anything to the user.

class My_Widget extends WP_Widget {
    // You static instance switch
    static $instance;

    function My_Widget() {
            // We set the static class var to true on the first run
            if ( ! $this->instance ) {
                    $this->instance = true;
            } 
            // abort silently for the second instance of the widget
            else {
                    return;
            }
        // widget actual processes
    }
    function form($instance) {
        // outputs the options form on admin
    }
    function update($new_instance, $old_instance) {
        // processes widget options to be saved
    }
    function widget($args, $instance) {
        // outputs the content of the widget
    }
}
register_widget('My_Widget');

Code taken from the related Widgets API Codex article


Handling the global widgets array

Another option might be to check the global array containing all registered widgets:

function wpse32103_show_widgets()
{
    $dump  = '<pre>';
    $dump .= var_export( $GLOBALS['wp_registered_widgets'], false );
    $dump .= '</pre>';

    return print $dump;
}
add_action( 'shutdown', 'wpse32103_show_widgets' );

The output of the associative array contains the name as key, appended by -2 (nr. is incremented). You could search through the array on the init or admin_init hook and simply unset if you have found a second instance. Maybe something like the following:

function wpse32103_show_widgets()
{
        global $wp_registered_widgets;

        // Go and search for your widgets name with the above written function
        $target = 'FILL IN YOUR FOUND ARRAY KEY HERE. Without -2 (or any other appending number)';

        // Container for your targeted widget(s)
        $unsets = array();
        foreach ( array_keys( $wp_registered_widgets ) as $widget )
        {
            // remove dashes
            $widget_check = str_replace( '-', '', $widget );
            // remove numbers
            $widget_check = preg_replace( '/[^0-9]/', '', $widget );

            // if we match, do it in our container
            if ( $widget_check === $target )
                $unsets[] = $widget;
        }

        // less than one element in the container: abort
        if ( ! count ( $unsets ) > 1 )
            return;

        // preserve first element
        array_shift( array_values( $unsets ) );

        // unset all left instances from the global array
        foreach ( $unsets as $unset )
            unset ( $wp_registered_widgets[ $unset ] );

        return;
}
add_action( 'init', 'wpse32103_show_widgets' );
share|improve this answer
    
The first approach is more to my liking, but I tried it and it didn't work. Did you try it yourself out of interest? –  matt Oct 26 '11 at 19:42
    
It should work. Could you do a var_dump( $instance );? I guess there's some typo or similiar. –  kaiser Oct 27 '11 at 1:00
    
Hi, it's showing null above each widget on the front end. But really, I want to prevent adding more than one widget in the Wordpress back end. Doing var_dump( $this->instance ); in the constructor for the widget also shows null for any/all instances. I've edited the question to clarify. –  matt Oct 27 '11 at 11:38
    
how would one make sure that the options array only contains one set of options for the one array instance? see the related question here wordpress.stackexchange.com/questions/125971/… –  user9 Dec 10 '13 at 21:05

Edit: Doh, just saw that you didn't want to use to the old code. Oh well, I'll leave it just in case it helps someone.

WP added multi widgets in 2.8. So, I tracked down a tutorial that covered how to make a widget in WP 2.7. Here's the code:

add_action("widgets_init", array('Widget_name', 'register'));
register_activation_hook( __FILE__, array('Widget_name', 'activate'));
register_deactivation_hook( __FILE__, array('Widget_name', 'deactivate'));
class Widget_name {
  function activate(){
    $data = array( 'option1' => 'Default value' ,'option2' => 55);
    if ( ! get_option('widget_name')){
      add_option('widget_name' , $data);
    } else {
      update_option('widget_name' , $data);
    }
  }
  function deactivate(){
    delete_option('widget_name');
  }
    function control(){
        $data = get_option('widget_name');
        ?>
        <p><label>Option 1<input name="widget_name_option1"
    type="text" value="<?php echo $data['option1']; ?>" /></label></p>
        <p><label>Option 2<input name="widget_name_option2"
    type="text" value="<?php echo $data['option2']; ?>" /></label></p>
        <?php
         if (isset($_POST['widget_name_option1'])){
            $data['option1'] = attribute_escape($_POST['widget_name_option1']);
            $data['option2'] = attribute_escape($_POST['widget_name_option2']);
            update_option('widget_name', $data);
        }
    }
  function widget($args){
    echo $args['before_widget'];
    echo $args['before_title'] . 'Your widget title' . $args['after_title'];
    echo 'I am your widget';
    echo $args['after_widget'];
  }
  function register(){
        wp_register_sidebar_widget( 'my_widget_id', 'Widget name', array('Widget_name', 'widget'));
    wp_register_widget_control( 'my_widget_id', 'Widget name', array('Widget_name', 'control'));
  }
}

I replaced the calls to register_sidebar_widget and register_widget_control with wp_register_sidebar_widget and wp_register_widget_control respectively, to fix warnings about using deprecated functions. Otherwise, this is a straight copy/paste from the tutorial I linked to.

share|improve this answer

You don't. It's too difficult to be worth it. It's how the JS editor thing works.

BUT: Create a Widget with no settings and allow setting it up on a different page. Like this:

// In your Widget use this form() method
public function form($instance){
    $settings_url = admin_url('options-general.php?page=SettingsPage');
    echo '<p>';
        echo 'To setup this <strong>Widget</strong> go to:<br />';
        echo '<a href="', $settings_url, '" target="_blank">';
            echo '<strong>Settings &raquo; Settings Page</strong>';
        echo '</a>';
    echo '</p>';
    return 'noform';
}

Use add_options_page to create the SettingsPage page for Widget management. And use get_option() to retrieve the settings for Widget Output.

Regards.

PS: If you need a full example, let me know.

share|improve this answer
    
Keep the rate hate flowing. I'd love hate comments too. Thanks ;) –  EarnestoDev Oct 27 '11 at 1:34
    
It's not hate, it's simply that you categorically affirm something that is not true. if(true) then {false} :o) –  brasofilo May 3 '12 at 20:14

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.